Adding some support for using "idle" to get changed events.
[libmpd.git] / src / libmpd-playlist.c
blob0dfdef7b45ff6c6854922700973be487db57cb27
1 /*
2 *Copyright (C) 2004-2007 Qball Cow <Qball@qballcow.nl>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, 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, 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 mpd_Song * mpd_playlist_get_current_song(MpdObj *mi)
189 if(!mpd_check_connected(mi))
191 debug_printf(DEBUG_ERROR, "Not Connected\n");
192 return NULL;
195 if(mpd_status_check(mi) != MPD_OK)
197 debug_printf(DEBUG_ERROR, "Failed to check status\n");
198 return NULL;
201 if(mi->CurrentSong != NULL && mi->CurrentSong->id != mi->status->songid)
203 debug_printf(DEBUG_WARNING, "Current song not up2date, updating\n");
204 mpd_freeSong(mi->CurrentSong);
205 mi->CurrentSong = NULL;
207 /* only update song when playing/pasing */
208 if(mi->CurrentSong == NULL &&
209 (mpd_player_get_state(mi) != MPD_PLAYER_STOP && mpd_player_get_state(mi) != MPD_PLAYER_UNKNOWN))
211 /* TODO: this to use the geT_current_song_id function */
212 mi->CurrentSong = mpd_playlist_get_song(mi, mpd_player_get_current_song_id(mi));
213 if(mi->CurrentSong == NULL)
215 debug_printf(DEBUG_ERROR, "Failed to grab song\n");
216 return NULL;
219 return mi->CurrentSong;
222 int mpd_playlist_clear(MpdObj *mi)
224 if(!mpd_check_connected(mi))
226 debug_printf(DEBUG_WARNING,"not connected\n");
227 return MPD_NOT_CONNECTED;
229 if(mpd_lock_conn(mi))
231 debug_printf(DEBUG_WARNING,"lock failed\n");
232 return MPD_LOCK_FAILED;
235 mpd_sendClearCommand(mi->connection);
236 mpd_finishCommand(mi->connection);
237 /* hack to make it update correctly when replacing 1 song */
238 mi->CurrentState.songid = -1;
239 /* unlock */
240 mpd_unlock_conn(mi);
241 mpd_status_update(mi);
242 return FALSE;
245 int mpd_playlist_shuffle(MpdObj *mi)
247 if(!mpd_check_connected(mi))
249 debug_printf(DEBUG_WARNING,"not connected\n");
250 return MPD_NOT_CONNECTED;
252 if(mpd_lock_conn(mi))
254 debug_printf(DEBUG_ERROR,"lock failed\n");
255 return MPD_LOCK_FAILED;
258 mpd_sendShuffleCommand(mi->connection);
259 mpd_finishCommand(mi->connection);
261 /* unlock */
262 mpd_unlock_conn(mi);
263 return FALSE;
268 int mpd_playlist_move_id(MpdObj *mi, int old_id, int new_id)
270 if(!mpd_check_connected(mi))
272 debug_printf(DEBUG_WARNING,"not connected\n");
273 return MPD_NOT_CONNECTED;
275 if(mpd_lock_conn(mi))
277 debug_printf(DEBUG_ERROR,"lock failed\n");
278 return MPD_LOCK_FAILED;
281 mpd_sendMoveIdCommand(mi->connection,old_id, new_id);
282 mpd_finishCommand(mi->connection);
284 /* unlock */
285 mpd_unlock_conn(mi);
286 return MPD_OK;
289 int mpd_playlist_move_pos(MpdObj *mi, int old_pos, int new_pos)
291 if(!mpd_check_connected(mi))
293 debug_printf(DEBUG_WARNING,"not connected\n");
294 return MPD_NOT_CONNECTED;
296 if(mpd_lock_conn(mi))
298 debug_printf(DEBUG_ERROR,"lock failed\n");
299 return MPD_LOCK_FAILED;
302 mpd_sendMoveCommand(mi->connection,old_pos, new_pos);
303 mpd_finishCommand(mi->connection);
305 /* unlock */
306 mpd_unlock_conn(mi);
307 return MPD_OK;
310 MpdData * mpd_playlist_get_changes(MpdObj *mi,int old_playlist_id)
312 MpdData *data = NULL;
313 mpd_InfoEntity *ent = NULL;
314 if(!mpd_check_connected(mi))
316 debug_printf(DEBUG_WARNING,"not connected\n");
317 return NULL;
319 if(mpd_lock_conn(mi))
321 debug_printf(DEBUG_WARNING,"lock failed\n");
322 return NULL;
325 if(old_playlist_id == -1)
327 debug_printf(DEBUG_INFO,"get fresh playlist\n");
328 mpd_sendPlChangesCommand (mi->connection, 0);
329 /* mpd_sendPlaylistIdCommand(mi->connection, -1); */
331 else
333 mpd_sendPlChangesCommand (mi->connection, old_playlist_id);
336 while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
338 if(ent->type == MPD_INFO_ENTITY_TYPE_SONG)
340 data = mpd_new_data_struct_append(data);
341 data->type = MPD_DATA_TYPE_SONG;
342 data->song = ent->info.song;
343 ent->info.song = NULL;
345 mpd_freeInfoEntity(ent);
347 mpd_finishCommand(mi->connection);
349 /* unlock */
350 if(mpd_unlock_conn(mi))
352 debug_printf(DEBUG_WARNING,"mpd_playlist_get_changes: unlock failed.\n");
353 mpd_data_free(data);
354 return NULL;
356 if(data == NULL)
358 return NULL;
360 return mpd_data_get_first(data);
365 MpdData * mpd_playlist_get_changes_posid(MpdObj *mi,int old_playlist_id)
367 MpdData *data = NULL;
368 mpd_InfoEntity *ent = NULL;
369 debug_printf(DEBUG_INFO, "Fetching using new plchangesposid command");
370 if(!mpd_check_connected(mi))
372 debug_printf(DEBUG_WARNING,"not connected\n");
373 return NULL;
375 if(mpd_lock_conn(mi))
377 debug_printf(DEBUG_WARNING,"lock failed\n");
378 return NULL;
381 if(old_playlist_id == -1)
383 debug_printf(DEBUG_INFO,"get fresh playlist\n");
384 mpd_sendPlChangesPosIdCommand (mi->connection, 0);
385 /* mpd_sendPlaylistIdCommand(mi->connection, -1); */
387 else
389 mpd_sendPlChangesPosIdCommand (mi->connection, old_playlist_id);
392 while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
394 if(ent->type == MPD_INFO_ENTITY_TYPE_SONG)
396 data = mpd_new_data_struct_append(data);
397 data->type = MPD_DATA_TYPE_SONG;
398 data->song = ent->info.song;
399 ent->info.song = NULL;
401 mpd_freeInfoEntity(ent);
403 mpd_finishCommand(mi->connection);
405 /* unlock */
406 if(mpd_unlock_conn(mi))
408 debug_printf(DEBUG_WARNING,"mpd_playlist_get_changes: unlock failed.\n");
409 mpd_data_free(data);
410 return NULL;
412 if(data == NULL)
414 return NULL;
416 return mpd_data_get_first(data);
419 int mpd_playlist_queue_add(MpdObj *mi,char *path)
421 if(!mpd_check_connected(mi))
423 debug_printf(DEBUG_WARNING,"not connected\n");
424 return MPD_NOT_CONNECTED;
426 if(path == NULL)
428 debug_printf(DEBUG_ERROR, "path != NULL Failed");
429 return MPD_ARGS_ERROR;
432 if(mi->queue == NULL)
434 mi->queue = mpd_new_queue_struct();
435 mi->queue->first = mi->queue;
436 mi->queue->next = NULL;
437 mi->queue->prev = NULL;
439 else
441 mi->queue->next = mpd_new_queue_struct();
442 mi->queue->next->first = mi->queue->first;
443 mi->queue->next->prev = mi->queue;
444 mi->queue = mi->queue->next;
445 mi->queue->next = NULL;
447 mi->queue->type = MPD_QUEUE_ADD;
448 mi->queue->path = strdup(path);
449 return MPD_OK;
452 int mpd_playlist_queue_load(MpdObj *mi,char *path)
454 if(!mpd_check_connected(mi))
456 debug_printf(DEBUG_WARNING,"not connected\n");
457 return MPD_NOT_CONNECTED;
459 if(path == NULL)
461 debug_printf(DEBUG_ERROR, "path != NULL Failed");
462 return MPD_ARGS_ERROR;
465 if(mi->queue == NULL)
467 mi->queue = mpd_new_queue_struct();
468 mi->queue->first = mi->queue;
469 mi->queue->next = NULL;
470 mi->queue->prev = NULL;
472 else
474 mi->queue->next = mpd_new_queue_struct();
475 mi->queue->next->first = mi->queue->first;
476 mi->queue->next->prev = mi->queue;
477 mi->queue = mi->queue->next;
478 mi->queue->next = NULL;
480 mi->queue->type = MPD_QUEUE_LOAD;
481 mi->queue->path = strdup(path);
482 return MPD_OK;
486 int mpd_playlist_queue_commit(MpdObj *mi)
488 if(mi->queue == NULL)
490 debug_printf(DEBUG_WARNING,"mi->queue is empty");
491 return MPD_PLAYLIST_QUEUE_EMPTY;
493 if(!mpd_check_connected(mi))
495 debug_printf(DEBUG_WARNING,"not connected\n");
496 return MPD_NOT_CONNECTED;
498 if(mpd_lock_conn(mi))
500 debug_printf(DEBUG_WARNING,"lock failed\n");
501 return MPD_LOCK_FAILED;
503 mpd_sendCommandListBegin(mi->connection);
504 /* get first item */
505 mi->queue = mi->queue->first;
506 while(mi->queue != NULL)
508 if(mi->queue->type == MPD_QUEUE_ADD)
510 if(mi->queue->path != NULL)
512 mpd_sendAddCommand(mi->connection, mi->queue->path);
515 else if(mi->queue->type == MPD_QUEUE_LOAD)
517 if(mi->queue->path != NULL)
519 mpd_sendLoadCommand(mi->connection, mi->queue->path);
522 else if (mi->queue->type == MPD_QUEUE_DELETE_ID)
524 if(mi->queue->id >= 0)
526 mpd_sendDeleteIdCommand(mi->connection, mi->queue->id);
529 else if (mi->queue->type == MPD_QUEUE_DELETE_POS)
531 if(mi->queue->id >= 0)
533 mpd_sendDeleteCommand(mi->connection, mi->queue->id);
537 mpd_queue_get_next(mi);
539 mpd_sendCommandListEnd(mi->connection);
540 mpd_finishCommand(mi->connection);
541 mpd_unlock_conn(mi);
542 mpd_status_update(mi);
543 return MPD_OK;
545 int mpd_playlist_queue_delete_id(MpdObj *mi,int id)
547 if(!mpd_check_connected(mi))
549 debug_printf(DEBUG_WARNING,"not connected\n");
550 return MPD_NOT_CONNECTED;
553 if(mi->queue == NULL)
555 mi->queue = mpd_new_queue_struct();
556 mi->queue->first = mi->queue;
557 mi->queue->next = NULL;
558 mi->queue->prev = NULL;
560 else
562 mi->queue->next = mpd_new_queue_struct();
563 mi->queue->next->first = mi->queue->first;
564 mi->queue->next->prev = mi->queue;
565 mi->queue = mi->queue->next;
566 mi->queue->next = NULL;
568 mi->queue->type = MPD_QUEUE_DELETE_ID;
569 mi->queue->id = id;
570 mi->queue->path = NULL;
571 return MPD_OK;
574 int mpd_playlist_queue_delete_pos(MpdObj *mi,int songpos)
576 if(!mpd_check_connected(mi))
578 debug_printf(DEBUG_WARNING,"mpd_playlist_add: not connected\n");
579 return MPD_NOT_CONNECTED;
582 if(mi->queue == NULL)
584 mi->queue = mpd_new_queue_struct();
585 mi->queue->first = mi->queue;
586 mi->queue->next = NULL;
587 mi->queue->prev = NULL;
589 else
591 mi->queue->next = mpd_new_queue_struct();
592 mi->queue->next->first = mi->queue->first;
593 mi->queue->next->prev = mi->queue;
594 mi->queue = mi->queue->next;
595 mi->queue->next = NULL;
597 mi->queue->type = MPD_QUEUE_DELETE_POS;
598 mi->queue->id = songpos;
599 mi->queue->path = NULL;
600 return MPD_OK;
603 int mpd_playlist_add_get_id(MpdObj *mi, char *path)
605 int songid = -1;
606 if(mi == NULL || path == NULL)
608 debug_printf(DEBUG_ERROR, "mi == NULL || path == NULL failed");
609 return MPD_ARGS_ERROR;
611 if(!mpd_check_connected(mi))
613 debug_printf(DEBUG_WARNING,"mpd_playlist_add: not connected\n");
614 return MPD_NOT_CONNECTED;
616 if(mpd_lock_conn(mi))
618 debug_printf(DEBUG_WARNING,"lock failed\n");
619 return MPD_LOCK_FAILED;
621 songid = mpd_sendAddIdCommand(mi->connection, path);
622 mpd_finishCommand(mi->connection);
624 mpd_unlock_conn(mi);
625 return songid;
628 void mpd_playlist_search_start(MpdObj *mi, int exact)
631 * Check argument
633 if(mi == NULL || exact > 1 || exact < 0)
635 debug_printf(DEBUG_ERROR, "Argument error");
636 return ;
638 if(!mpd_check_connected(mi))
640 debug_printf(DEBUG_ERROR, "Not Connected\n");
641 return ;
643 if(!mpd_server_check_version(mi, 0,12,1))
645 debug_printf(DEBUG_ERROR, "Advanced search requires mpd 0.12.2 or higher");
646 return ;
648 /* lock, so we can work on mi->connection */
649 if(mpd_lock_conn(mi) != MPD_OK)
651 debug_printf(DEBUG_ERROR, "Failed to lock connection");
652 return ;
654 mpd_startPlaylistSearch(mi->connection, exact);
655 /* Set search type */
656 mi->search_type = (exact)? MPD_SEARCH_TYPE_PLAYLIST_FIND:MPD_SEARCH_TYPE_PLAYLIST_SEARCH;
657 /* unlock, let the error handler handle any possible error.
659 mpd_unlock_conn(mi);
660 return;
663 void mpd_playlist_search_add_constraint(MpdObj *mi, mpd_TagItems field,const char *value)
665 mpd_database_search_add_constraint(mi, field, value);
667 MpdData * mpd_playlist_search_commit(MpdObj *mi)
669 mpd_InfoEntity *ent = NULL;
670 MpdData *data = NULL;
671 if(!mpd_check_connected(mi))
673 debug_printf(DEBUG_WARNING,"not connected\n");
674 return NULL;
676 if(mi->search_type < MPD_SEARCH_TYPE_PLAYLIST_FIND )
678 debug_printf(DEBUG_ERROR, "no or wrong search in progress to commit");
679 return NULL;
681 if(mpd_lock_conn(mi))
683 debug_printf(DEBUG_ERROR,"lock failed\n");
684 return NULL;
686 mpd_commitSearch(mi->connection);
687 while (( ent = mpd_getNextInfoEntity(mi->connection)) != NULL)
689 if(ent->type == MPD_INFO_ENTITY_TYPE_SONG)
691 data = mpd_new_data_struct_append(data);
692 data->type = MPD_DATA_TYPE_SONG;
693 data->song = ent->info.song;
694 ent->info.song = NULL;
696 mpd_freeInfoEntity(ent);
698 mpd_finishCommand(mi->connection);
700 * reset search type
702 mi->search_type = MPD_SEARCH_TYPE_NONE;
703 mi->search_field = MPD_TAG_ITEM_ARTIST;
704 /* unlock */
705 if(mpd_unlock_conn(mi))
707 debug_printf(DEBUG_ERROR, "Failed to unlock connection");
708 if(data)mpd_data_free(data);
709 return NULL;
711 if(data == NULL)
713 return NULL;
715 return mpd_data_get_first(data);