Hack in priority support. Patch 1.
[libmpd.git] / src / libmpd-playlist.c
blob7230dafc86d3457dcc64eb32ff3674009a2b4e9e
1 /* libmpd (high level libmpdclient library)
2 * Copyright (C) 2004-2009 Qball Cow <qball@sarine.nl>
3 * Project homepage: http://gmpcwiki.sarine.nl/
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.
20 #include <stdio.h>
21 #include <stdlib.h>
22 #define __USE_GNU
24 #include <string.h>
25 #include <stdarg.h>
26 #include <config.h>
27 #include "debug_printf.h"
28 #include "libmpd.h"
29 #include "libmpd-internal.h"
32 int mpd_playlist_get_playlist_length(MpdObj *mi)
34 if(!mpd_check_connected(mi))
36 debug_printf(DEBUG_WARNING,"not connected\n");
37 return MPD_NOT_CONNECTED;
39 if(mpd_status_check(mi) != MPD_OK)
41 debug_printf(DEBUG_ERROR,"Failed grabbing status\n");
42 return MPD_STATUS_FAILED;
44 return mi->status->playlistLength;
47 long long mpd_playlist_get_old_playlist_id(MpdObj *mi)
49 return mi->OldState.playlistid;
52 long long mpd_playlist_get_playlist_id(MpdObj *mi)
54 if(!mpd_check_connected(mi))
56 debug_printf(DEBUG_WARNING,"not connected\n");
57 return MPD_NOT_CONNECTED;
59 if(mpd_status_check(mi) != MPD_OK)
61 debug_printf(DEBUG_WARNING,"Failed grabbing status\n");
62 return MPD_STATUS_FAILED;
64 return mi->status->playlist;
66 int mpd_playlist_add(MpdObj *mi,const char *path)
68 int retv = mpd_playlist_queue_add(mi, path);
69 if(retv != MPD_OK) return retv;
70 return mpd_playlist_queue_commit(mi);
73 int mpd_playlist_delete_id(MpdObj *mi, int songid)
75 int retv = mpd_playlist_queue_delete_id(mi, songid);
76 if(retv != MPD_OK) return retv;
77 return mpd_playlist_queue_commit(mi);
80 int mpd_playlist_delete_pos(MpdObj *mi, int songpos)
82 int retv = mpd_playlist_queue_delete_pos(mi, songpos);
83 if(retv != MPD_OK) return retv;
84 return mpd_playlist_queue_commit(mi);
86 /*******************************************************************************
87 * PLAYLIST
89 mpd_Song * mpd_playlist_get_song(MpdObj *mi, int songid)
91 mpd_Song *song = NULL;
92 mpd_InfoEntity *ent = NULL;
93 if(songid < 0){
94 debug_printf(DEBUG_ERROR, "songid < 0 Failed");
95 return NULL;
97 if(!mpd_check_connected(mi))
99 debug_printf(DEBUG_ERROR, "Not Connected\n");
100 return NULL;
103 if(mpd_lock_conn(mi))
105 return NULL;
107 debug_printf(DEBUG_INFO, "Trying to grab song with id: %i\n", songid);
108 mpd_sendPlaylistIdCommand(mi->connection, songid);
109 ent = mpd_getNextInfoEntity(mi->connection);
110 mpd_finishCommand(mi->connection);
112 if(mpd_unlock_conn(mi))
114 if(ent) mpd_freeInfoEntity(ent);
115 return NULL;
118 if(ent == NULL)
120 debug_printf(DEBUG_ERROR, "Failed to grab song from mpd\n");
121 return NULL;
124 if(ent->type != MPD_INFO_ENTITY_TYPE_SONG)
126 mpd_freeInfoEntity(ent);
127 debug_printf(DEBUG_ERROR, "Failed to grab correct song type from mpd\n");
128 return NULL;
130 song = ent->info.song;
131 ent->info.song = NULL;
133 mpd_freeInfoEntity(ent);
135 return song;
138 mpd_Song * mpd_playlist_get_song_from_pos(MpdObj *mi, int songpos)
140 mpd_Song *song = NULL;
141 mpd_InfoEntity *ent = NULL;
142 if(songpos < 0){
143 debug_printf(DEBUG_ERROR, "songpos < 0 Failed");
144 return NULL;
146 if(!mpd_check_connected(mi))
148 debug_printf(DEBUG_ERROR, "Not Connected\n");
149 return NULL;
152 if(mpd_lock_conn(mi))
154 return NULL;
156 debug_printf(DEBUG_INFO, "Trying to grab song with id: %i\n", songpos);
157 mpd_sendPlaylistInfoCommand(mi->connection, songpos);
158 ent = mpd_getNextInfoEntity(mi->connection);
159 mpd_finishCommand(mi->connection);
161 if(mpd_unlock_conn(mi))
163 /*TODO free entity. for now this can never happen */
164 return NULL;
167 if(ent == NULL)
169 debug_printf(DEBUG_ERROR, "Failed to grab song from mpd\n");
170 return NULL;
173 if(ent->type != MPD_INFO_ENTITY_TYPE_SONG)
175 mpd_freeInfoEntity(ent);
176 debug_printf(DEBUG_ERROR, "Failed to grab corect song type from mpd\n");
177 return NULL;
179 song = ent->info.song;
180 ent->info.song = NULL;
182 mpd_freeInfoEntity(ent);
184 return song;
187 MpdData * mpd_playlist_get_song_from_pos_range(MpdObj *mi, int start, int stop)
189 MpdData *data = NULL;
190 int i;
191 mpd_InfoEntity *ent = NULL;
192 if(!mpd_check_connected(mi))
194 debug_printf(DEBUG_ERROR, "Not Connected\n");
195 return NULL;
197 if(mpd_status_check(mi) != MPD_OK)
199 debug_printf(DEBUG_ERROR,"Failed grabbing status\n");
200 return NULL;
203 if(mpd_lock_conn(mi))
205 return NULL;
207 /* Don't check outside playlist length */
208 if(!(stop < mi->status->playlistLength)) {
209 stop = mi->status->playlistLength -1;
211 mpd_sendCommandListBegin(mi->connection);
212 for(i=start; i <= stop; i++){
213 mpd_sendPlaylistInfoCommand(mi->connection, i);
215 mpd_sendCommandListEnd(mi->connection);
216 while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
218 if(ent->type == MPD_INFO_ENTITY_TYPE_SONG)
220 data = mpd_new_data_struct_append(data);
221 data->type = MPD_DATA_TYPE_SONG;
222 data->song = ent->info.song;
223 ent->info.song = NULL;
225 mpd_freeInfoEntity(ent);
227 mpd_finishCommand(mi->connection);
229 if(mpd_unlock_conn(mi))
231 /*TODO free entity. for now this can never happen */
232 return NULL;
234 return data;
237 mpd_Song * mpd_playlist_get_current_song(MpdObj *mi)
239 if(!mpd_check_connected(mi))
241 debug_printf(DEBUG_WARNING, "Not Connected\n");
242 return NULL;
245 if(mpd_status_check(mi) != MPD_OK)
247 debug_printf(DEBUG_ERROR, "Failed to check status\n");
248 return NULL;
251 if(mi->CurrentSong != NULL && mi->CurrentSong->id != mi->status->songid)
253 debug_printf(DEBUG_WARNING, "Current song not up2date, updating\n");
254 mpd_freeSong(mi->CurrentSong);
255 mi->CurrentSong = NULL;
257 /* only update song when playing/pasing */
258 if(mi->CurrentSong == NULL &&
259 (mpd_player_get_state(mi) != MPD_PLAYER_STOP && mpd_player_get_state(mi) != MPD_PLAYER_UNKNOWN))
261 /* TODO: this to use the geT_current_song_id function */
262 mi->CurrentSong = mpd_playlist_get_song(mi, mpd_player_get_current_song_id(mi));
263 if(mi->CurrentSong == NULL)
265 debug_printf(DEBUG_ERROR, "Failed to grab song\n");
266 return NULL;
269 return mi->CurrentSong;
272 int mpd_playlist_clear(MpdObj *mi)
274 if(!mpd_check_connected(mi))
276 debug_printf(DEBUG_WARNING,"not connected\n");
277 return MPD_NOT_CONNECTED;
279 if(mpd_lock_conn(mi))
281 debug_printf(DEBUG_WARNING,"lock failed\n");
282 return MPD_LOCK_FAILED;
285 mpd_sendClearCommand(mi->connection);
286 mpd_finishCommand(mi->connection);
287 /* hack to make it update correctly when replacing 1 song */
288 mi->CurrentState.songid = -1;
289 /* unlock */
290 mpd_unlock_conn(mi);
291 mpd_status_update(mi);
292 return FALSE;
295 int mpd_playlist_shuffle(MpdObj *mi)
297 if(!mpd_check_connected(mi))
299 debug_printf(DEBUG_WARNING,"not connected\n");
300 return MPD_NOT_CONNECTED;
302 if(mpd_lock_conn(mi))
304 debug_printf(DEBUG_ERROR,"lock failed\n");
305 return MPD_LOCK_FAILED;
308 mpd_sendShuffleCommand(mi->connection);
309 mpd_finishCommand(mi->connection);
311 /* unlock */
312 mpd_unlock_conn(mi);
313 return FALSE;
318 int mpd_playlist_move_id(MpdObj *mi, int old_id, int new_id)
320 if(!mpd_check_connected(mi))
322 debug_printf(DEBUG_WARNING,"not connected\n");
323 return MPD_NOT_CONNECTED;
325 if(mpd_lock_conn(mi))
327 debug_printf(DEBUG_ERROR,"lock failed\n");
328 return MPD_LOCK_FAILED;
331 mpd_sendMoveIdCommand(mi->connection,old_id, new_id);
332 mpd_finishCommand(mi->connection);
334 /* unlock */
335 mpd_unlock_conn(mi);
336 return MPD_OK;
339 int mpd_playlist_set_priority(MpdObj *mi, int song_id, int priority)
341 if(!mpd_check_connected(mi))
343 debug_printf(DEBUG_WARNING,"not connected\n");
344 return MPD_NOT_CONNECTED;
346 if(mpd_lock_conn(mi))
348 debug_printf(DEBUG_ERROR,"lock failed\n");
349 return MPD_LOCK_FAILED;
352 mpd_sendSetPrioId(mi->connection,priority, song_id);
353 mpd_finishCommand(mi->connection);
355 /* unlock */
356 mpd_unlock_conn(mi);
357 return MPD_OK;
360 int mpd_playlist_move_pos(MpdObj *mi, int old_pos, int new_pos)
362 if(!mpd_check_connected(mi))
364 debug_printf(DEBUG_WARNING,"not connected\n");
365 return MPD_NOT_CONNECTED;
367 if(mpd_lock_conn(mi))
369 debug_printf(DEBUG_ERROR,"lock failed\n");
370 return MPD_LOCK_FAILED;
373 mpd_sendMoveCommand(mi->connection,old_pos, new_pos);
374 mpd_finishCommand(mi->connection);
376 /* unlock */
377 mpd_unlock_conn(mi);
378 return MPD_OK;
381 MpdData * mpd_playlist_get_changes(MpdObj *mi,int old_playlist_id)
383 MpdData *data = NULL;
384 mpd_InfoEntity *ent = NULL;
385 if(!mpd_check_connected(mi))
387 debug_printf(DEBUG_WARNING,"not connected\n");
388 return NULL;
390 if(mpd_lock_conn(mi))
392 debug_printf(DEBUG_WARNING,"lock failed\n");
393 return NULL;
396 if(old_playlist_id == -1)
398 debug_printf(DEBUG_INFO,"get fresh playlist\n");
399 mpd_sendPlChangesCommand (mi->connection, 0);
400 /* mpd_sendPlaylistIdCommand(mi->connection, -1); */
402 else
404 mpd_sendPlChangesCommand (mi->connection, old_playlist_id);
407 while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
409 if(ent->type == MPD_INFO_ENTITY_TYPE_SONG)
411 data = mpd_new_data_struct_append(data);
412 data->type = MPD_DATA_TYPE_SONG;
413 data->song = ent->info.song;
414 ent->info.song = NULL;
416 mpd_freeInfoEntity(ent);
418 mpd_finishCommand(mi->connection);
420 /* unlock */
421 if(mpd_unlock_conn(mi))
423 debug_printf(DEBUG_WARNING,"mpd_playlist_get_changes: unlock failed.\n");
424 mpd_data_free(data);
425 return NULL;
427 if(data == NULL)
429 return NULL;
431 return mpd_data_get_first(data);
436 MpdData * mpd_playlist_get_changes_posid(MpdObj *mi,int old_playlist_id)
438 MpdData *data = NULL;
439 mpd_InfoEntity *ent = NULL;
440 debug_printf(DEBUG_INFO, "Fetching using new plchangesposid command");
441 if(!mpd_check_connected(mi))
443 debug_printf(DEBUG_WARNING,"not connected\n");
444 return NULL;
446 if(mpd_lock_conn(mi))
448 debug_printf(DEBUG_WARNING,"lock failed\n");
449 return NULL;
452 if(old_playlist_id == -1)
454 debug_printf(DEBUG_INFO,"get fresh playlist\n");
455 mpd_sendPlChangesPosIdCommand (mi->connection, 0);
456 /* mpd_sendPlaylistIdCommand(mi->connection, -1); */
458 else
460 mpd_sendPlChangesPosIdCommand (mi->connection, old_playlist_id);
463 while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
465 if(ent->type == MPD_INFO_ENTITY_TYPE_SONG)
467 data = mpd_new_data_struct_append(data);
468 data->type = MPD_DATA_TYPE_SONG;
469 data->song = ent->info.song;
470 ent->info.song = NULL;
472 mpd_freeInfoEntity(ent);
474 mpd_finishCommand(mi->connection);
476 /* unlock */
477 if(mpd_unlock_conn(mi))
479 debug_printf(DEBUG_WARNING,"mpd_playlist_get_changes: unlock failed.\n");
480 mpd_data_free(data);
481 return NULL;
483 if(data == NULL)
485 return NULL;
487 return mpd_data_get_first(data);
490 int mpd_playlist_queue_add(MpdObj *mi,const char *path)
492 if(!mpd_check_connected(mi))
494 debug_printf(DEBUG_WARNING,"not connected\n");
495 return MPD_NOT_CONNECTED;
497 if(path == NULL)
499 debug_printf(DEBUG_ERROR, "path != NULL Failed");
500 return MPD_ARGS_ERROR;
503 if(mi->queue == NULL)
505 mi->queue = mpd_new_queue_struct();
506 mi->queue->first = mi->queue;
507 mi->queue->next = NULL;
508 mi->queue->prev = NULL;
510 else
512 mi->queue->next = mpd_new_queue_struct();
513 mi->queue->next->first = mi->queue->first;
514 mi->queue->next->prev = mi->queue;
515 mi->queue = mi->queue->next;
516 mi->queue->next = NULL;
518 mi->queue->type = MPD_QUEUE_ADD;
519 mi->queue->path = strdup(path);
520 return MPD_OK;
523 int mpd_playlist_queue_load(MpdObj *mi,const char *path)
525 if(!mpd_check_connected(mi))
527 debug_printf(DEBUG_WARNING,"not connected\n");
528 return MPD_NOT_CONNECTED;
530 if(path == NULL)
532 debug_printf(DEBUG_ERROR, "path != NULL Failed");
533 return MPD_ARGS_ERROR;
536 if(mi->queue == NULL)
538 mi->queue = mpd_new_queue_struct();
539 mi->queue->first = mi->queue;
540 mi->queue->next = NULL;
541 mi->queue->prev = NULL;
543 else
545 mi->queue->next = mpd_new_queue_struct();
546 mi->queue->next->first = mi->queue->first;
547 mi->queue->next->prev = mi->queue;
548 mi->queue = mi->queue->next;
549 mi->queue->next = NULL;
551 mi->queue->type = MPD_QUEUE_LOAD;
552 mi->queue->path = strdup(path);
553 return MPD_OK;
557 int mpd_playlist_queue_commit(MpdObj *mi)
559 if(!mpd_check_connected(mi))
561 debug_printf(DEBUG_WARNING,"not connected\n");
562 return MPD_NOT_CONNECTED;
564 if(mi->queue == NULL)
566 debug_printf(DEBUG_WARNING,"mi->queue is empty");
567 return MPD_PLAYLIST_QUEUE_EMPTY;
569 if(mpd_lock_conn(mi))
571 debug_printf(DEBUG_WARNING,"lock failed\n");
572 return MPD_LOCK_FAILED;
574 mpd_sendCommandListBegin(mi->connection);
575 /* get first item */
576 mi->queue = mi->queue->first;
577 while(mi->queue != NULL)
579 if(mi->queue->type == MPD_QUEUE_ADD)
581 if(mi->queue->path != NULL)
583 mpd_sendAddCommand(mi->connection, mi->queue->path);
586 else if(mi->queue->type == MPD_QUEUE_LOAD)
588 if(mi->queue->path != NULL)
590 mpd_sendLoadCommand(mi->connection, mi->queue->path);
593 else if (mi->queue->type == MPD_QUEUE_DELETE_ID)
595 if(mi->queue->id >= 0)
597 mpd_sendDeleteIdCommand(mi->connection, mi->queue->id);
600 else if (mi->queue->type == MPD_QUEUE_DELETE_POS)
602 if(mi->queue->id >= 0)
604 mpd_sendDeleteCommand(mi->connection, mi->queue->id);
608 mpd_queue_get_next(mi);
610 mpd_sendCommandListEnd(mi->connection);
611 mpd_finishCommand(mi->connection);
615 mpd_unlock_conn(mi);
616 mpd_status_update(mi);
617 return MPD_OK;
619 int mpd_playlist_queue_delete_id(MpdObj *mi,int id)
621 if(!mpd_check_connected(mi))
623 debug_printf(DEBUG_WARNING,"not connected\n");
624 return MPD_NOT_CONNECTED;
627 if(mi->queue == NULL)
629 mi->queue = mpd_new_queue_struct();
630 mi->queue->first = mi->queue;
631 mi->queue->next = NULL;
632 mi->queue->prev = NULL;
634 else
636 mi->queue->next = mpd_new_queue_struct();
637 mi->queue->next->first = mi->queue->first;
638 mi->queue->next->prev = mi->queue;
639 mi->queue = mi->queue->next;
640 mi->queue->next = NULL;
642 mi->queue->type = MPD_QUEUE_DELETE_ID;
643 mi->queue->id = id;
644 mi->queue->path = NULL;
645 return MPD_OK;
648 int mpd_playlist_queue_delete_pos(MpdObj *mi,int songpos)
650 if(!mpd_check_connected(mi))
652 debug_printf(DEBUG_WARNING,"mpd_playlist_add: not connected\n");
653 return MPD_NOT_CONNECTED;
656 if(mi->queue == NULL)
658 mi->queue = mpd_new_queue_struct();
659 mi->queue->first = mi->queue;
660 mi->queue->next = NULL;
661 mi->queue->prev = NULL;
663 else
665 mi->queue->next = mpd_new_queue_struct();
666 mi->queue->next->first = mi->queue->first;
667 mi->queue->next->prev = mi->queue;
668 mi->queue = mi->queue->next;
669 mi->queue->next = NULL;
671 mi->queue->type = MPD_QUEUE_DELETE_POS;
672 mi->queue->id = songpos;
673 mi->queue->path = NULL;
674 return MPD_OK;
677 int mpd_playlist_add_get_id(MpdObj *mi,const char *path)
679 int songid = -1;
680 if(mi == NULL || path == NULL)
682 debug_printf(DEBUG_ERROR, "mi == NULL || path == NULL failed");
683 return MPD_ARGS_ERROR;
685 if(!mpd_check_connected(mi))
687 debug_printf(DEBUG_WARNING,"mpd_playlist_add: not connected\n");
688 return MPD_NOT_CONNECTED;
690 if(mpd_lock_conn(mi))
692 debug_printf(DEBUG_WARNING,"lock failed\n");
693 return MPD_LOCK_FAILED;
695 songid = mpd_sendAddIdCommand(mi->connection, path);
696 mpd_finishCommand(mi->connection);
698 mpd_unlock_conn(mi);
699 return songid;
702 void mpd_playlist_search_start(MpdObj *mi, int exact)
705 * Check argument
707 if(mi == NULL || exact > 1 || exact < 0)
709 debug_printf(DEBUG_ERROR, "Argument error");
710 return ;
712 if(!mpd_check_connected(mi))
714 debug_printf(DEBUG_ERROR, "Not Connected\n");
715 return ;
717 if(!mpd_server_check_version(mi, 0,12,1))
719 debug_printf(DEBUG_ERROR, "Advanced search requires mpd 0.12.2 or higher");
720 return ;
722 /* lock, so we can work on mi->connection */
723 if(mpd_lock_conn(mi) != MPD_OK)
725 debug_printf(DEBUG_ERROR, "Failed to lock connection");
726 return ;
728 mpd_startPlaylistSearch(mi->connection, exact);
729 /* Set search type */
730 mi->search_type = (exact)? MPD_SEARCH_TYPE_PLAYLIST_FIND:MPD_SEARCH_TYPE_PLAYLIST_SEARCH;
731 /* unlock, let the error handler handle any possible error.
733 mpd_unlock_conn(mi);
734 return;
737 void mpd_playlist_search_add_constraint(MpdObj *mi, mpd_TagItems field,const char *value)
739 mpd_database_search_add_constraint(mi, field, value);
741 MpdData * mpd_playlist_search_commit(MpdObj *mi)
743 mpd_InfoEntity *ent = NULL;
744 MpdData *data = NULL;
745 if(!mpd_check_connected(mi))
747 debug_printf(DEBUG_WARNING,"not connected\n");
748 return NULL;
750 if(mi->search_type < MPD_SEARCH_TYPE_PLAYLIST_FIND )
752 debug_printf(DEBUG_ERROR, "no or wrong search in progress to commit");
753 return NULL;
755 if(mpd_lock_conn(mi))
757 debug_printf(DEBUG_ERROR,"lock failed\n");
758 return NULL;
760 mpd_commitSearch(mi->connection);
761 while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
763 if(ent->type == MPD_INFO_ENTITY_TYPE_SONG)
765 data = mpd_new_data_struct_append(data);
766 data->type = MPD_DATA_TYPE_SONG;
767 data->song = ent->info.song;
768 ent->info.song = NULL;
770 mpd_freeInfoEntity(ent);
772 mpd_finishCommand(mi->connection);
774 * reset search type
776 mi->search_type = MPD_SEARCH_TYPE_NONE;
777 mi->search_field = MPD_TAG_ITEM_ARTIST;
778 /* unlock */
779 if(mpd_unlock_conn(mi))
781 debug_printf(DEBUG_ERROR, "Failed to unlock connection");
782 if(data)mpd_data_free(data);
783 return NULL;
785 if(data == NULL)
787 return NULL;
789 return mpd_data_get_first(data);
793 int mpd_playlist_load(MpdObj *mi, const char *path)
795 int retv = MPD_OK;
796 if(!mpd_check_connected(mi))
798 debug_printf(DEBUG_WARNING,"mpd_playlist_load: not connected\n");
799 return MPD_NOT_CONNECTED;
801 if(mpd_lock_conn(mi))
803 debug_printf(DEBUG_ERROR,"lock failed\n");
804 return MPD_LOCK_FAILED;
806 mpd_sendLoadCommand(mi->connection,path);
807 mpd_finishCommand(mi->connection);
808 if(mi->connection->errorCode == MPD_ACK_ERROR_NO_EXIST)
810 debug_printf(DEBUG_WARNING, "mpd_playlist_load: failed to load playlist\n");
811 mpd_clearError(mi->connection);
812 retv = MPD_PLAYLIST_LOAD_FAILED;
815 if(mpd_unlock_conn(mi))
817 debug_printf(DEBUG_ERROR, "Failed to unlock connection");
818 return MPD_LOCK_FAILED;
820 return retv;