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.
27 #include "debug_printf.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 /*******************************************************************************
89 mpd_Song
* mpd_playlist_get_song(MpdObj
*mi
, int songid
)
91 mpd_Song
*song
= NULL
;
92 mpd_InfoEntity
*ent
= NULL
;
94 debug_printf(DEBUG_ERROR
, "songid < 0 Failed");
97 if(!mpd_check_connected(mi
))
99 debug_printf(DEBUG_ERROR
, "Not Connected\n");
103 if(mpd_lock_conn(mi
))
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
);
120 debug_printf(DEBUG_ERROR
, "Failed to grab song from mpd\n");
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");
130 song
= ent
->info
.song
;
131 ent
->info
.song
= NULL
;
133 mpd_freeInfoEntity(ent
);
138 mpd_Song
* mpd_playlist_get_song_from_pos(MpdObj
*mi
, int songpos
)
140 mpd_Song
*song
= NULL
;
141 mpd_InfoEntity
*ent
= NULL
;
143 debug_printf(DEBUG_ERROR
, "songpos < 0 Failed");
146 if(!mpd_check_connected(mi
))
148 debug_printf(DEBUG_ERROR
, "Not Connected\n");
152 if(mpd_lock_conn(mi
))
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 */
169 debug_printf(DEBUG_ERROR
, "Failed to grab song from mpd\n");
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");
179 song
= ent
->info
.song
;
180 ent
->info
.song
= NULL
;
182 mpd_freeInfoEntity(ent
);
187 MpdData
* mpd_playlist_get_song_from_pos_range(MpdObj
*mi
, int start
, int stop
)
189 MpdData
*data
= NULL
;
191 mpd_InfoEntity
*ent
= NULL
;
192 if(!mpd_check_connected(mi
))
194 debug_printf(DEBUG_ERROR
, "Not Connected\n");
197 if(mpd_status_check(mi
) != MPD_OK
)
199 debug_printf(DEBUG_ERROR
,"Failed grabbing status\n");
203 if(mpd_lock_conn(mi
))
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 */
237 mpd_Song
* mpd_playlist_get_current_song(MpdObj
*mi
)
239 if(!mpd_check_connected(mi
))
241 debug_printf(DEBUG_WARNING
, "Not Connected\n");
245 if(mpd_status_check(mi
) != MPD_OK
)
247 debug_printf(DEBUG_ERROR
, "Failed to check status\n");
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");
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;
291 mpd_status_update(mi
);
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
);
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
);
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_server_check_command_allowed(mi
, "prioid") != MPD_SERVER_COMMAND_ALLOWED
)
348 return MPD_SERVER_NOT_SUPPORTED
;
350 if(mpd_lock_conn(mi
))
352 debug_printf(DEBUG_ERROR
,"lock failed\n");
353 return MPD_LOCK_FAILED
;
356 mpd_sendSetPrioId(mi
->connection
,priority
, song_id
);
357 mpd_finishCommand(mi
->connection
);
364 int mpd_playlist_move_pos(MpdObj
*mi
, int old_pos
, int new_pos
)
366 if(!mpd_check_connected(mi
))
368 debug_printf(DEBUG_WARNING
,"not connected\n");
369 return MPD_NOT_CONNECTED
;
371 if(mpd_lock_conn(mi
))
373 debug_printf(DEBUG_ERROR
,"lock failed\n");
374 return MPD_LOCK_FAILED
;
377 mpd_sendMoveCommand(mi
->connection
,old_pos
, new_pos
);
378 mpd_finishCommand(mi
->connection
);
385 MpdData
* mpd_playlist_get_changes(MpdObj
*mi
,int old_playlist_id
)
387 MpdData
*data
= NULL
;
388 mpd_InfoEntity
*ent
= NULL
;
389 if(!mpd_check_connected(mi
))
391 debug_printf(DEBUG_WARNING
,"not connected\n");
394 if(mpd_lock_conn(mi
))
396 debug_printf(DEBUG_WARNING
,"lock failed\n");
400 if(old_playlist_id
== -1)
402 debug_printf(DEBUG_INFO
,"get fresh playlist\n");
403 mpd_sendPlChangesCommand (mi
->connection
, 0);
404 /* mpd_sendPlaylistIdCommand(mi->connection, -1); */
408 mpd_sendPlChangesCommand (mi
->connection
, old_playlist_id
);
411 while (( ent
= mpd_getNextInfoEntity(mi
->connection
)) != NULL
)
413 if(ent
->type
== MPD_INFO_ENTITY_TYPE_SONG
)
415 data
= mpd_new_data_struct_append(data
);
416 data
->type
= MPD_DATA_TYPE_SONG
;
417 data
->song
= ent
->info
.song
;
418 ent
->info
.song
= NULL
;
420 mpd_freeInfoEntity(ent
);
422 mpd_finishCommand(mi
->connection
);
425 if(mpd_unlock_conn(mi
))
427 debug_printf(DEBUG_WARNING
,"mpd_playlist_get_changes: unlock failed.\n");
435 return mpd_data_get_first(data
);
440 MpdData
* mpd_playlist_get_changes_posid(MpdObj
*mi
,int old_playlist_id
)
442 MpdData
*data
= NULL
;
443 mpd_InfoEntity
*ent
= NULL
;
444 debug_printf(DEBUG_INFO
, "Fetching using new plchangesposid command");
445 if(!mpd_check_connected(mi
))
447 debug_printf(DEBUG_WARNING
,"not connected\n");
450 if(mpd_lock_conn(mi
))
452 debug_printf(DEBUG_WARNING
,"lock failed\n");
456 if(old_playlist_id
== -1)
458 debug_printf(DEBUG_INFO
,"get fresh playlist\n");
459 mpd_sendPlChangesPosIdCommand (mi
->connection
, 0);
460 /* mpd_sendPlaylistIdCommand(mi->connection, -1); */
464 mpd_sendPlChangesPosIdCommand (mi
->connection
, old_playlist_id
);
467 while (( ent
= mpd_getNextInfoEntity(mi
->connection
)) != NULL
)
469 if(ent
->type
== MPD_INFO_ENTITY_TYPE_SONG
)
471 data
= mpd_new_data_struct_append(data
);
472 data
->type
= MPD_DATA_TYPE_SONG
;
473 data
->song
= ent
->info
.song
;
474 ent
->info
.song
= NULL
;
476 mpd_freeInfoEntity(ent
);
478 mpd_finishCommand(mi
->connection
);
481 if(mpd_unlock_conn(mi
))
483 debug_printf(DEBUG_WARNING
,"mpd_playlist_get_changes: unlock failed.\n");
491 return mpd_data_get_first(data
);
494 int mpd_playlist_queue_add(MpdObj
*mi
,const char *path
)
496 if(!mpd_check_connected(mi
))
498 debug_printf(DEBUG_WARNING
,"not connected\n");
499 return MPD_NOT_CONNECTED
;
503 debug_printf(DEBUG_ERROR
, "path != NULL Failed");
504 return MPD_ARGS_ERROR
;
507 if(mi
->queue
== NULL
)
509 mi
->queue
= mpd_new_queue_struct();
510 mi
->queue
->first
= mi
->queue
;
511 mi
->queue
->next
= NULL
;
512 mi
->queue
->prev
= NULL
;
516 mi
->queue
->next
= mpd_new_queue_struct();
517 mi
->queue
->next
->first
= mi
->queue
->first
;
518 mi
->queue
->next
->prev
= mi
->queue
;
519 mi
->queue
= mi
->queue
->next
;
520 mi
->queue
->next
= NULL
;
522 mi
->queue
->type
= MPD_QUEUE_ADD
;
523 mi
->queue
->path
= strdup(path
);
527 int mpd_playlist_queue_load(MpdObj
*mi
,const char *path
)
529 if(!mpd_check_connected(mi
))
531 debug_printf(DEBUG_WARNING
,"not connected\n");
532 return MPD_NOT_CONNECTED
;
536 debug_printf(DEBUG_ERROR
, "path != NULL Failed");
537 return MPD_ARGS_ERROR
;
540 if(mi
->queue
== NULL
)
542 mi
->queue
= mpd_new_queue_struct();
543 mi
->queue
->first
= mi
->queue
;
544 mi
->queue
->next
= NULL
;
545 mi
->queue
->prev
= NULL
;
549 mi
->queue
->next
= mpd_new_queue_struct();
550 mi
->queue
->next
->first
= mi
->queue
->first
;
551 mi
->queue
->next
->prev
= mi
->queue
;
552 mi
->queue
= mi
->queue
->next
;
553 mi
->queue
->next
= NULL
;
555 mi
->queue
->type
= MPD_QUEUE_LOAD
;
556 mi
->queue
->path
= strdup(path
);
561 int mpd_playlist_queue_commit(MpdObj
*mi
)
563 if(!mpd_check_connected(mi
))
565 debug_printf(DEBUG_WARNING
,"not connected\n");
566 return MPD_NOT_CONNECTED
;
568 if(mi
->queue
== NULL
)
570 debug_printf(DEBUG_WARNING
,"mi->queue is empty");
571 return MPD_PLAYLIST_QUEUE_EMPTY
;
573 if(mpd_lock_conn(mi
))
575 debug_printf(DEBUG_WARNING
,"lock failed\n");
576 return MPD_LOCK_FAILED
;
578 mpd_sendCommandListBegin(mi
->connection
);
580 mi
->queue
= mi
->queue
->first
;
581 while(mi
->queue
!= NULL
)
583 if(mi
->queue
->type
== MPD_QUEUE_ADD
)
585 if(mi
->queue
->path
!= NULL
)
587 mpd_sendAddCommand(mi
->connection
, mi
->queue
->path
);
590 else if(mi
->queue
->type
== MPD_QUEUE_LOAD
)
592 if(mi
->queue
->path
!= NULL
)
594 mpd_sendLoadCommand(mi
->connection
, mi
->queue
->path
);
597 else if (mi
->queue
->type
== MPD_QUEUE_DELETE_ID
)
599 if(mi
->queue
->id
>= 0)
601 mpd_sendDeleteIdCommand(mi
->connection
, mi
->queue
->id
);
604 else if (mi
->queue
->type
== MPD_QUEUE_DELETE_POS
)
606 if(mi
->queue
->id
>= 0)
608 mpd_sendDeleteCommand(mi
->connection
, mi
->queue
->id
);
612 mpd_queue_get_next(mi
);
614 mpd_sendCommandListEnd(mi
->connection
);
615 mpd_finishCommand(mi
->connection
);
620 mpd_status_update(mi
);
623 int mpd_playlist_queue_delete_id(MpdObj
*mi
,int id
)
625 if(!mpd_check_connected(mi
))
627 debug_printf(DEBUG_WARNING
,"not connected\n");
628 return MPD_NOT_CONNECTED
;
631 if(mi
->queue
== NULL
)
633 mi
->queue
= mpd_new_queue_struct();
634 mi
->queue
->first
= mi
->queue
;
635 mi
->queue
->next
= NULL
;
636 mi
->queue
->prev
= NULL
;
640 mi
->queue
->next
= mpd_new_queue_struct();
641 mi
->queue
->next
->first
= mi
->queue
->first
;
642 mi
->queue
->next
->prev
= mi
->queue
;
643 mi
->queue
= mi
->queue
->next
;
644 mi
->queue
->next
= NULL
;
646 mi
->queue
->type
= MPD_QUEUE_DELETE_ID
;
648 mi
->queue
->path
= NULL
;
652 int mpd_playlist_queue_delete_pos(MpdObj
*mi
,int songpos
)
654 if(!mpd_check_connected(mi
))
656 debug_printf(DEBUG_WARNING
,"mpd_playlist_add: not connected\n");
657 return MPD_NOT_CONNECTED
;
660 if(mi
->queue
== NULL
)
662 mi
->queue
= mpd_new_queue_struct();
663 mi
->queue
->first
= mi
->queue
;
664 mi
->queue
->next
= NULL
;
665 mi
->queue
->prev
= NULL
;
669 mi
->queue
->next
= mpd_new_queue_struct();
670 mi
->queue
->next
->first
= mi
->queue
->first
;
671 mi
->queue
->next
->prev
= mi
->queue
;
672 mi
->queue
= mi
->queue
->next
;
673 mi
->queue
->next
= NULL
;
675 mi
->queue
->type
= MPD_QUEUE_DELETE_POS
;
676 mi
->queue
->id
= songpos
;
677 mi
->queue
->path
= NULL
;
681 int mpd_playlist_add_get_id(MpdObj
*mi
,const char *path
)
684 if(mi
== NULL
|| path
== NULL
)
686 debug_printf(DEBUG_ERROR
, "mi == NULL || path == NULL failed");
687 return MPD_ARGS_ERROR
;
689 if(!mpd_check_connected(mi
))
691 debug_printf(DEBUG_WARNING
,"mpd_playlist_add: not connected\n");
692 return MPD_NOT_CONNECTED
;
694 if(mpd_lock_conn(mi
))
696 debug_printf(DEBUG_WARNING
,"lock failed\n");
697 return MPD_LOCK_FAILED
;
699 songid
= mpd_sendAddIdCommand(mi
->connection
, path
);
700 mpd_finishCommand(mi
->connection
);
706 void mpd_playlist_search_start(MpdObj
*mi
, int exact
)
711 if(mi
== NULL
|| exact
> 1 || exact
< 0)
713 debug_printf(DEBUG_ERROR
, "Argument error");
716 if(!mpd_check_connected(mi
))
718 debug_printf(DEBUG_ERROR
, "Not Connected\n");
721 if(!mpd_server_check_version(mi
, 0,12,1))
723 debug_printf(DEBUG_ERROR
, "Advanced search requires mpd 0.12.2 or higher");
726 /* lock, so we can work on mi->connection */
727 if(mpd_lock_conn(mi
) != MPD_OK
)
729 debug_printf(DEBUG_ERROR
, "Failed to lock connection");
732 mpd_startPlaylistSearch(mi
->connection
, exact
);
733 /* Set search type */
734 mi
->search_type
= (exact
)? MPD_SEARCH_TYPE_PLAYLIST_FIND
:MPD_SEARCH_TYPE_PLAYLIST_SEARCH
;
735 /* unlock, let the error handler handle any possible error.
741 void mpd_playlist_search_add_constraint(MpdObj
*mi
, mpd_TagItems field
,const char *value
)
743 mpd_database_search_add_constraint(mi
, field
, value
);
745 MpdData
* mpd_playlist_search_commit(MpdObj
*mi
)
747 mpd_InfoEntity
*ent
= NULL
;
748 MpdData
*data
= NULL
;
749 if(!mpd_check_connected(mi
))
751 debug_printf(DEBUG_WARNING
,"not connected\n");
754 if(mi
->search_type
< MPD_SEARCH_TYPE_PLAYLIST_FIND
)
756 debug_printf(DEBUG_ERROR
, "no or wrong search in progress to commit");
759 if(mpd_lock_conn(mi
))
761 debug_printf(DEBUG_ERROR
,"lock failed\n");
764 mpd_commitSearch(mi
->connection
);
765 while (( ent
= mpd_getNextInfoEntity(mi
->connection
)) != NULL
)
767 if(ent
->type
== MPD_INFO_ENTITY_TYPE_SONG
)
769 data
= mpd_new_data_struct_append(data
);
770 data
->type
= MPD_DATA_TYPE_SONG
;
771 data
->song
= ent
->info
.song
;
772 ent
->info
.song
= NULL
;
774 mpd_freeInfoEntity(ent
);
776 mpd_finishCommand(mi
->connection
);
780 mi
->search_type
= MPD_SEARCH_TYPE_NONE
;
781 mi
->search_field
= MPD_TAG_ITEM_ARTIST
;
783 if(mpd_unlock_conn(mi
))
785 debug_printf(DEBUG_ERROR
, "Failed to unlock connection");
786 if(data
)mpd_data_free(data
);
793 return mpd_data_get_first(data
);
797 int mpd_playlist_load(MpdObj
*mi
, const char *path
)
800 if(!mpd_check_connected(mi
))
802 debug_printf(DEBUG_WARNING
,"mpd_playlist_load: not connected\n");
803 return MPD_NOT_CONNECTED
;
805 if(mpd_lock_conn(mi
))
807 debug_printf(DEBUG_ERROR
,"lock failed\n");
808 return MPD_LOCK_FAILED
;
810 mpd_sendLoadCommand(mi
->connection
,path
);
811 mpd_finishCommand(mi
->connection
);
812 if(mi
->connection
->errorCode
== MPD_ACK_ERROR_NO_EXIST
)
814 debug_printf(DEBUG_WARNING
, "mpd_playlist_load: failed to load playlist\n");
815 mpd_clearError(mi
->connection
);
816 retv
= MPD_PLAYLIST_LOAD_FAILED
;
819 if(mpd_unlock_conn(mi
))
821 debug_printf(DEBUG_ERROR
, "Failed to unlock connection");
822 return MPD_LOCK_FAILED
;