Code

a688162a1832640f0938051d4b1a08afe90e6176
[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_utils.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
38 #define ENABLE_SONG_ID
39 #define ENABLE_PLCHANGES
41 #define BUFSIZE 1024
43 static bool
44 MPD_ERROR(const struct mpdclient *client)
45 {
46         return client->connection == NULL ||
47                 mpd_connection_get_error(client->connection) != MPD_ERROR_SUCCESS;
48 }
50 /* filelist sorting functions */
51 static gint
52 compare_filelistentry(gconstpointer filelist_entry1,
53                           gconstpointer filelist_entry2)
54 {
55         const struct mpd_entity *e1, *e2;
56         int n = 0;
58         e1 = ((const struct filelist_entry *)filelist_entry1)->entity;
59         e2 = ((const struct filelist_entry *)filelist_entry2)->entity;
61         if (e1 != NULL && e2 != NULL &&
62             mpd_entity_get_type(e1) == mpd_entity_get_type(e2)) {
63                 switch (mpd_entity_get_type(e1)) {
64                 case MPD_ENTITY_TYPE_UNKNOWN:
65                         break;
66                 case MPD_ENTITY_TYPE_DIRECTORY:
67                         n = g_utf8_collate(mpd_directory_get_path(mpd_entity_get_directory(e1)),
68                                            mpd_directory_get_path(mpd_entity_get_directory(e2)));
69                         break;
70                 case MPD_ENTITY_TYPE_SONG:
71                         break;
72                 case MPD_ENTITY_TYPE_PLAYLIST:
73                         n = g_utf8_collate(mpd_playlist_get_path(mpd_entity_get_playlist(e1)),
74                                            mpd_playlist_get_path(mpd_entity_get_playlist(e2)));
75                 }
76         }
77         return n;
78 }
80 /* sort by list-format */
81 gint
82 compare_filelistentry_format(gconstpointer filelist_entry1,
83                              gconstpointer filelist_entry2)
84 {
85         const struct mpd_entity *e1, *e2;
86         char key1[BUFSIZE], key2[BUFSIZE];
87         int n = 0;
89         e1 = ((const struct filelist_entry *)filelist_entry1)->entity;
90         e2 = ((const struct filelist_entry *)filelist_entry2)->entity;
92         if (e1 && e2 &&
93             mpd_entity_get_type(e1) == MPD_ENTITY_TYPE_SONG &&
94             mpd_entity_get_type(e2) == MPD_ENTITY_TYPE_SONG) {
95                 strfsong(key1, BUFSIZE, options.list_format, mpd_entity_get_song(e1));
96                 strfsong(key2, BUFSIZE, options.list_format, mpd_entity_get_song(e2));
97                 n = strcmp(key1,key2);
98         }
100         return n;
104 /****************************************************************************/
105 /*** mpdclient functions ****************************************************/
106 /****************************************************************************/
108 static gint
109 mpdclient_handle_error(struct mpdclient *c)
111         enum mpd_error error = mpd_connection_get_error(c->connection);
113         assert(error != MPD_ERROR_SUCCESS);
115         if (error == MPD_ERROR_SERVER &&
116             mpd_connection_get_server_error(c->connection) == MPD_SERVER_ERROR_PERMISSION &&
117             screen_auth(c) == 0)
118                 return 0;
120         if (error == MPD_ERROR_SERVER)
121                 error = error | (mpd_connection_get_server_error(c->connection) << 8);
123         for (GList *list = c->error_callbacks; list != NULL;
124              list = list->next) {
125                 mpdc_error_cb_t cb = list->data;
126                 cb(c, error, mpd_connection_get_error_message(c->connection));
127         }
129         if (!mpd_connection_clear_error(c->connection))
130                 mpdclient_disconnect(c);
132         return error;
135 gint
136 mpdclient_finish_command(struct mpdclient *c)
138         return mpd_response_finish(c->connection)
139                 ? 0 : mpdclient_handle_error(c);
142 struct mpdclient *
143 mpdclient_new(void)
145         struct mpdclient *c;
147         c = g_new0(struct mpdclient, 1);
148         playlist_init(&c->playlist);
149         c->volume = MPD_STATUS_NO_VOLUME;
151         return c;
154 void
155 mpdclient_free(struct mpdclient *c)
157         mpdclient_disconnect(c);
159         mpdclient_playlist_free(&c->playlist);
161         g_list_free(c->error_callbacks);
162         g_list_free(c->playlist_callbacks);
163         g_list_free(c->browse_callbacks);
164         g_free(c);
167 gint
168 mpdclient_disconnect(struct mpdclient *c)
170         if (c->connection)
171                 mpd_connection_free(c->connection);
172         c->connection = NULL;
174         if (c->status)
175                 mpd_status_free(c->status);
176         c->status = NULL;
178         playlist_clear(&c->playlist);
180         if (c->song)
181                 c->song = NULL;
183         return 0;
186 gint
187 mpdclient_connect(struct mpdclient *c,
188                   const gchar *host,
189                   gint port,
190                   gfloat _timeout,
191                   const gchar *password)
193         gint retval = 0;
195         /* close any open connection */
196         if( c->connection )
197                 mpdclient_disconnect(c);
199         /* connect to MPD */
200         c->connection = mpd_connection_new(host, port, _timeout * 1000);
201         if (c->connection == NULL)
202                 g_error("Out of memory");
204         if (mpd_connection_get_error(c->connection) != MPD_ERROR_SUCCESS) {
205                 retval = mpdclient_handle_error(c);
206                 if (retval != 0) {
207                         mpd_connection_free(c->connection);
208                         c->connection = NULL;
209                 }
211                 return retval;
212         }
214         /* send password */
215         if( password ) {
216                 mpd_send_password(c->connection, password);
217                 retval = mpdclient_finish_command(c);
218         }
219         c->need_update = TRUE;
221         return retval;
224 gint
225 mpdclient_update(struct mpdclient *c)
227         gint retval = 0;
229         c->volume = MPD_STATUS_NO_VOLUME;
231         if (MPD_ERROR(c))
232                 return -1;
234         /* free the old status */
235         if (c->status)
236                 mpd_status_free(c->status);
238         /* retrieve new status */
239         c->status = mpd_run_status(c->connection);
240         if (c->status == NULL)
241                 return mpdclient_handle_error(c);
243         if (c->updatingdb &&
244             c->updatingdb != mpd_status_get_update_id(c->status))
245                 mpdclient_browse_callback(c, BROWSE_DB_UPDATED, NULL);
247         c->updatingdb = mpd_status_get_update_id(c->status);
248         c->volume = mpd_status_get_volume(c->status);
250         /* check if the playlist needs an update */
251         if (c->playlist.id != mpd_status_get_queue_version(c->status)) {
252                 if (playlist_is_empty(&c->playlist))
253                         retval = mpdclient_playlist_update_changes(c);
254                 else
255                         retval = mpdclient_playlist_update(c);
256         }
258         /* update the current song */
259         if (!c->song || mpd_status_get_song_id(c->status)) {
260                 c->song = playlist_get_song(c, mpd_status_get_song_pos(c->status));
261         }
263         c->need_update = FALSE;
265         return retval;
269 /****************************************************************************/
270 /*** MPD Commands  **********************************************************/
271 /****************************************************************************/
273 gint
274 mpdclient_cmd_play(struct mpdclient *c, gint idx)
276 #ifdef ENABLE_SONG_ID
277         struct mpd_song *song = playlist_get_song(c, idx);
279         if (MPD_ERROR(c))
280                 return -1;
282         if (song)
283                 mpd_send_play_id(c->connection, mpd_song_get_id(song));
284         else
285                 mpd_send_play(c->connection);
286 #else
287         if (MPD_ERROR(c))
288                 return -1;
290         mpd_sendPlayCommand(c->connection, idx);
291 #endif
292         c->need_update = TRUE;
293         return mpdclient_finish_command(c);
296 gint
297 mpdclient_cmd_pause(struct mpdclient *c, gint value)
299         if (MPD_ERROR(c))
300                 return -1;
302         mpd_send_pause(c->connection, value);
303         return mpdclient_finish_command(c);
306 gint
307 mpdclient_cmd_crop(struct mpdclient *c)
309         struct mpd_status *status;
310         bool playing;
311         int length, current;
313         if (MPD_ERROR(c))
314                 return -1;
316         status = mpd_run_status(c->connection);
317         if (status == NULL)
318                 return mpdclient_handle_error(c);
320         playing = mpd_status_get_state(status) == MPD_STATE_PLAY ||
321                 mpd_status_get_state(status) == MPD_STATE_PAUSE;
322         length = mpd_status_get_queue_length(status);
323         current = mpd_status_get_song_pos(status);
325         mpd_status_free(status);
327         if (!playing || length < 2)
328                 return 0;
330         mpd_command_list_begin(c->connection, false);
332         while (--length >= 0)
333                 if (length != current)
334                         mpd_send_delete(c->connection, length);
336         mpd_command_list_end(c->connection);
338         return mpdclient_finish_command(c);
341 gint
342 mpdclient_cmd_stop(struct mpdclient *c)
344         if (MPD_ERROR(c))
345                 return -1;
347         mpd_send_stop(c->connection);
348         return mpdclient_finish_command(c);
351 gint
352 mpdclient_cmd_next(struct mpdclient *c)
354         if (MPD_ERROR(c))
355                 return -1;
357         mpd_send_next(c->connection);
358         c->need_update = TRUE;
359         return mpdclient_finish_command(c);
362 gint
363 mpdclient_cmd_prev(struct mpdclient *c)
365         if (MPD_ERROR(c))
366                 return -1;
368         mpd_send_previous(c->connection);
369         c->need_update = TRUE;
370         return mpdclient_finish_command(c);
373 gint
374 mpdclient_cmd_seek(struct mpdclient *c, gint id, gint pos)
376         if (MPD_ERROR(c))
377                 return -1;
379         mpd_send_seek_id(c->connection, id, pos);
380         return mpdclient_finish_command(c);
383 gint
384 mpdclient_cmd_shuffle(struct mpdclient *c)
386         if (MPD_ERROR(c))
387                 return -1;
389         mpd_send_shuffle(c->connection);
390         c->need_update = TRUE;
391         return mpdclient_finish_command(c);
394 gint
395 mpdclient_cmd_shuffle_range(struct mpdclient *c, guint start, guint end)
397         mpd_send_shuffle_range(c->connection, start, end);
398         c->need_update = TRUE;
399         return mpdclient_finish_command(c);
402 gint
403 mpdclient_cmd_clear(struct mpdclient *c)
405         gint retval = 0;
407         if (MPD_ERROR(c))
408                 return -1;
410         mpd_send_clear(c->connection);
411         retval = mpdclient_finish_command(c);
412         /* call playlist updated callback */
413         mpdclient_playlist_callback(c, PLAYLIST_EVENT_CLEAR, NULL);
414         c->need_update = TRUE;
415         return retval;
418 gint
419 mpdclient_cmd_repeat(struct mpdclient *c, gint value)
421         if (MPD_ERROR(c))
422                 return -1;
424         mpd_send_repeat(c->connection, value);
425         return mpdclient_finish_command(c);
428 gint
429 mpdclient_cmd_random(struct mpdclient *c, gint value)
431         if (MPD_ERROR(c))
432                 return -1;
434         mpd_send_random(c->connection, value);
435         return mpdclient_finish_command(c);
438 gint
439 mpdclient_cmd_single(struct mpdclient *c, gint value)
441         if (MPD_ERROR(c))
442                 return -1;
444         mpd_send_single(c->connection, value);
445         return mpdclient_finish_command(c);
448 gint
449 mpdclient_cmd_consume(struct mpdclient *c, gint value)
451         if (MPD_ERROR(c))
452                 return -1;
454         mpd_send_consume(c->connection, value);
455         return mpdclient_finish_command(c);
458 gint
459 mpdclient_cmd_crossfade(struct mpdclient *c, gint value)
461         if (MPD_ERROR(c))
462                 return -1;
464         mpd_send_crossfade(c->connection, value);
465         return mpdclient_finish_command(c);
468 gint
469 mpdclient_cmd_db_update(struct mpdclient *c, const gchar *path)
471         gint ret;
473         if (MPD_ERROR(c))
474                 return -1;
476         mpd_send_update(c->connection, path ? path : "");
477         ret = mpdclient_finish_command(c);
479         if (ret == 0)
480                 /* set updatingDb to make sure the browse callback
481                    gets called even if the update has finished before
482                    status is updated */
483                 c->updatingdb = 1;
485         return ret;
488 gint
489 mpdclient_cmd_volume(struct mpdclient *c, gint value)
491         if (MPD_ERROR(c))
492                 return -1;
494         mpd_send_set_volume(c->connection, value);
495         return mpdclient_finish_command(c);
498 gint mpdclient_cmd_volume_up(struct mpdclient *c)
500         if (MPD_ERROR(c))
501                 return -1;
503         if (c->status == NULL ||
504             mpd_status_get_volume(c->status) == MPD_STATUS_NO_VOLUME)
505                 return 0;
507         if (c->volume == MPD_STATUS_NO_VOLUME)
508                 c->volume = mpd_status_get_volume(c->status);
510         if (c->volume >= 100)
511                 return 0;
513         return mpdclient_cmd_volume(c, ++c->volume);
516 gint mpdclient_cmd_volume_down(struct mpdclient *c)
518         if (MPD_ERROR(c))
519                 return -1;
521         if (c->status == NULL ||
522             mpd_status_get_volume(c->status) == MPD_STATUS_NO_VOLUME)
523                 return 0;
525         if (c->volume == MPD_STATUS_NO_VOLUME)
526                 c->volume = mpd_status_get_volume(c->status);
528         if (c->volume <= 0)
529                 return 0;
531         return mpdclient_cmd_volume(c, --c->volume);
534 gint
535 mpdclient_cmd_add_path(struct mpdclient *c, const gchar *path_utf8)
537         if (MPD_ERROR(c))
538                 return -1;
540         mpd_send_add(c->connection, path_utf8);
541         return mpdclient_finish_command(c);
544 gint
545 mpdclient_cmd_add(struct mpdclient *c, const struct mpd_song *song)
547         gint retval = 0;
549         if (MPD_ERROR(c))
550                 return -1;
552         if (song == NULL)
553                 return -1;
555         /* send the add command to mpd */
556         mpd_send_add(c->connection, mpd_song_get_uri(song));
557         if( (retval=mpdclient_finish_command(c)) )
558                 return retval;
560 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD
561         /* add the song to playlist */
562         playlist_append(&c->playlist, song);
564         /* increment the playlist id, so we don't retrieve a new playlist */
565         c->playlist.id++;
567         /* call playlist updated callback */
568         mpdclient_playlist_callback(c, PLAYLIST_EVENT_ADD, (gpointer) song);
569 #else
570         c->need_update = TRUE;
571 #endif
573         return 0;
576 gint
577 mpdclient_cmd_delete(struct mpdclient *c, gint idx)
579         gint retval = 0;
580         struct mpd_song *song;
582         if (MPD_ERROR(c))
583                 return -1;
585         if (idx < 0 || (guint)idx >= playlist_length(&c->playlist))
586                 return -1;
588         song = playlist_get(&c->playlist, idx);
590         /* send the delete command to mpd */
591 #ifdef ENABLE_SONG_ID
592         mpd_send_delete_id(c->connection, mpd_song_get_id(song));
593 #else
594         mpd_send_delete(c->connection, idx);
595 #endif
596         if( (retval=mpdclient_finish_command(c)) )
597                 return retval;
599 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
600         /* increment the playlist id, so we don't retrieve a new playlist */
601         c->playlist.id++;
603         /* remove the song from the playlist */
604         playlist_remove_reuse(&c->playlist, idx);
606         /* call playlist updated callback */
607         mpdclient_playlist_callback(c, PLAYLIST_EVENT_DELETE, (gpointer) song);
609         /* remove references to the song */
610         if (c->song == song) {
611                 c->song = NULL;
612                 c->need_update = TRUE;
613         }
615         mpd_song_free(song);
617 #else
618         c->need_update = TRUE;
619 #endif
621         return 0;
624 gint
625 mpdclient_cmd_move(struct mpdclient *c, gint old_index, gint new_index)
627         gint n;
628         struct mpd_song *song1, *song2;
630         if (MPD_ERROR(c))
631                 return -1;
633         if (old_index == new_index || new_index < 0 ||
634             (guint)new_index >= c->playlist.list->len)
635                 return -1;
637         song1 = playlist_get(&c->playlist, old_index);
638         song2 = playlist_get(&c->playlist, new_index);
640         /* send the move command to mpd */
641 #ifdef ENABLE_SONG_ID
642         mpd_send_swap_id(c->connection,
643                          mpd_song_get_id(song1), mpd_song_get_id(song2));
644 #else
645         mpd_send_move(c->connection, old_index, new_index);
646 #endif
647         if( (n=mpdclient_finish_command(c)) )
648                 return n;
650 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
651         /* update the playlist */
652         playlist_swap(&c->playlist, old_index, new_index);
654         /* increment the playlist id, so we don't retrieve a new playlist */
655         c->playlist.id++;
657 #else
658         c->need_update = TRUE;
659 #endif
661         /* call playlist updated callback */
662         mpdclient_playlist_callback(c, PLAYLIST_EVENT_MOVE, (gpointer) &new_index);
664         return 0;
667 gint
668 mpdclient_cmd_save_playlist(struct mpdclient *c, const gchar *filename_utf8)
670         gint retval = 0;
672         if (MPD_ERROR(c))
673                 return -1;
675         mpd_send_save(c->connection, filename_utf8);
676         if ((retval = mpdclient_finish_command(c)) == 0)
677                 mpdclient_browse_callback(c, BROWSE_PLAYLIST_SAVED, NULL);
678         return retval;
681 gint
682 mpdclient_cmd_load_playlist(struct mpdclient *c, const gchar *filename_utf8)
684         if (MPD_ERROR(c))
685                 return -1;
687         mpd_send_load(c->connection, filename_utf8);
688         c->need_update = TRUE;
689         return mpdclient_finish_command(c);
692 gint
693 mpdclient_cmd_delete_playlist(struct mpdclient *c, const gchar *filename_utf8)
695         gint retval = 0;
697         if (MPD_ERROR(c))
698                 return -1;
700         mpd_send_rm(c->connection, filename_utf8);
701         if ((retval = mpdclient_finish_command(c)) == 0)
702                 mpdclient_browse_callback(c, BROWSE_PLAYLIST_DELETED, NULL);
703         return retval;
707 /****************************************************************************/
708 /*** Callback management functions ******************************************/
709 /****************************************************************************/
711 static void
712 do_list_callbacks(struct mpdclient *c, GList *list, gint event, gpointer data)
714         while (list) {
715                 mpdc_list_cb_t fn = list->data;
717                 fn(c, event, data);
718                 list = list->next;
719         }
722 void
723 mpdclient_playlist_callback(struct mpdclient *c, int event, gpointer data)
725         do_list_callbacks(c, c->playlist_callbacks, event, data);
728 void
729 mpdclient_install_playlist_callback(struct mpdclient *c,mpdc_list_cb_t cb)
731         c->playlist_callbacks = g_list_append(c->playlist_callbacks, cb);
734 void
735 mpdclient_remove_playlist_callback(struct mpdclient *c, mpdc_list_cb_t cb)
737         c->playlist_callbacks = g_list_remove(c->playlist_callbacks, cb);
740 void
741 mpdclient_browse_callback(struct mpdclient *c, int event, gpointer data)
743         do_list_callbacks(c, c->browse_callbacks, event, data);
747 void
748 mpdclient_install_browse_callback(struct mpdclient *c,mpdc_list_cb_t cb)
750         c->browse_callbacks = g_list_append(c->browse_callbacks, cb);
753 void
754 mpdclient_remove_browse_callback(struct mpdclient *c, mpdc_list_cb_t cb)
756         c->browse_callbacks = g_list_remove(c->browse_callbacks, cb);
759 void
760 mpdclient_install_error_callback(struct mpdclient *c, mpdc_error_cb_t cb)
762         c->error_callbacks = g_list_append(c->error_callbacks, cb);
765 void
766 mpdclient_remove_error_callback(struct mpdclient *c, mpdc_error_cb_t cb)
768         c->error_callbacks = g_list_remove(c->error_callbacks, cb);
772 /****************************************************************************/
773 /*** Playlist management functions ******************************************/
774 /****************************************************************************/
776 /* update playlist */
777 gint
778 mpdclient_playlist_update(struct mpdclient *c)
780         struct mpd_entity *entity;
782         if (MPD_ERROR(c))
783                 return -1;
785         playlist_clear(&c->playlist);
787         mpd_send_list_queue_meta(c->connection);
788         while ((entity = mpd_recv_entity(c->connection))) {
789                 if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG)
790                         playlist_append(&c->playlist, mpd_entity_get_song(entity));
792                 mpd_entity_free(entity);
793         }
795         c->playlist.id = mpd_status_get_queue_version(c->status);
796         c->song = NULL;
798         /* call playlist updated callbacks */
799         mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
801         return mpdclient_finish_command(c);
804 #ifdef ENABLE_PLCHANGES
806 /* update playlist (plchanges) */
807 gint
808 mpdclient_playlist_update_changes(struct mpdclient *c)
810         struct mpd_song *song;
811         guint length;
813         if (MPD_ERROR(c))
814                 return -1;
816         mpd_send_queue_changes_meta(c->connection, c->playlist.id);
818         while ((song = mpd_recv_song(c->connection)) != NULL) {
819                 int pos = mpd_song_get_pos(song);
821                 if (pos >= 0 && (guint)pos < c->playlist.list->len) {
822                         /* update song */
823                         playlist_replace(&c->playlist, pos, song);
824                 } else {
825                         /* add a new song */
826                         playlist_append(&c->playlist, song);
827                 }
829                 mpd_song_free(song);
830         }
832         /* remove trailing songs */
834         length = mpd_status_get_queue_length(c->status);
835         while (length < c->playlist.list->len) {
836                 guint pos = c->playlist.list->len - 1;
838                 /* Remove the last playlist entry */
839                 playlist_remove(&c->playlist, pos);
840         }
842         c->song = NULL;
843         c->playlist.id = mpd_status_get_queue_version(c->status);
845         mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
847         return 0;
850 #else
851 gint
852 mpdclient_playlist_update_changes(struct mpdclient *c)
854         return mpdclient_playlist_update(c);
856 #endif
859 /****************************************************************************/
860 /*** Filelist functions *****************************************************/
861 /****************************************************************************/
863 struct filelist *
864 mpdclient_filelist_get(struct mpdclient *c, const gchar *path)
866         struct filelist *filelist;
867         struct mpd_entity *entity;
869         if (MPD_ERROR(c))
870                 return NULL;
872         mpd_send_list_meta(c->connection, path);
873         filelist = filelist_new();
874         if (path && path[0] && strcmp(path, "/"))
875                 /* add a dummy entry for ./.. */
876                 filelist_append(filelist, NULL);
878         while ((entity = mpd_recv_entity(c->connection)) != NULL)
879                 filelist_append(filelist, entity);
881         /* If there's an error, ignore it.  We'll return an empty filelist. */
882         mpdclient_finish_command(c);
884         filelist_sort_dir_play(filelist, compare_filelistentry);
886         return filelist;
889 static struct filelist *
890 mpdclient_recv_filelist_response(struct mpdclient *c)
892         struct filelist *filelist;
893         struct mpd_entity *entity;
895         filelist = filelist_new();
897         while ((entity = mpd_recv_entity(c->connection)) != NULL)
898                 filelist_append(filelist, entity);
900         if (mpdclient_finish_command(c)) {
901                 filelist_free(filelist);
902                 return NULL;
903         }
905         return filelist;
908 struct filelist *
909 mpdclient_filelist_search(struct mpdclient *c,
910                           int exact_match,
911                           enum mpd_tag_type tag,
912                           gchar *filter_utf8)
914         if (MPD_ERROR(c))
915                 return NULL;
917         mpd_search_db_songs(c->connection, exact_match);
918         mpd_search_add_tag_constraint(c->connection, MPD_OPERATOR_DEFAULT,
919                                       tag, filter_utf8);
920         mpd_search_commit(c->connection);
922         return mpdclient_recv_filelist_response(c);
925 int
926 mpdclient_filelist_add_all(struct mpdclient *c, struct filelist *fl)
928         guint i;
930         if (MPD_ERROR(c))
931                 return -1;
933         if (filelist_is_empty(fl))
934                 return 0;
936         mpd_command_list_begin(c->connection, false);
938         for (i = 0; i < filelist_length(fl); ++i) {
939                 struct filelist_entry *entry = filelist_get(fl, i);
940                 struct mpd_entity *entity  = entry->entity;
942                 if (entity != NULL &&
943                     mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
944                         const struct mpd_song *song =
945                                 mpd_entity_get_song(entity);
946                         const char *uri = mpd_song_get_uri(song);
948                         if (uri != NULL)
949                                 mpd_send_add(c->connection, uri);
950                 }
951         }
953         mpd_command_list_end(c->connection);
954         return mpdclient_finish_command(c);
957 GList *
958 mpdclient_get_artists(struct mpdclient *c)
960         GList *list = NULL;
961         struct mpd_pair *pair;
963         if (MPD_ERROR(c))
964                return NULL;
966         mpd_search_db_tags(c->connection, MPD_TAG_ARTIST);
967         mpd_search_commit(c->connection);
969         while ((pair = mpd_recv_pair_tag(c->connection,
970                                          MPD_TAG_ARTIST)) != NULL) {
971                 list = g_list_append(list, g_strdup(pair->value));
972                 mpd_return_pair(c->connection, pair);
973         }
975         if (mpdclient_finish_command(c))
976                 return string_list_free(list);
978         return list;
981 GList *
982 mpdclient_get_albums(struct mpdclient *c, const gchar *artist_utf8)
984         GList *list = NULL;
985         struct mpd_pair *pair;
987         if (MPD_ERROR(c))
988                return NULL;
990         mpd_search_db_tags(c->connection, MPD_TAG_ALBUM);
991         if (artist_utf8 != NULL)
992                 mpd_search_add_tag_constraint(c->connection,
993                                               MPD_OPERATOR_DEFAULT,
994                                               MPD_TAG_ARTIST, artist_utf8);
995         mpd_search_commit(c->connection);
997         while ((pair = mpd_recv_pair_tag(c->connection,
998                                          MPD_TAG_ALBUM)) != NULL) {
999                 list = g_list_append(list, g_strdup(pair->value));
1000                 mpd_return_pair(c->connection, pair);
1001         }
1003         if (mpdclient_finish_command(c))
1004                 return string_list_free(list);
1006         return list;