1 /***************************************************************************
2 * Copyright (C) 2008-2009 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
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 *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
33 const char *MPD::Message::PartOfSongsAdded
= "Only part of requested songs' list added to playlist!";
34 const char *MPD::Message::FullPlaylist
= "Playlist is full!";
35 const char *MPD::Message::FunctionDisabledFilteringEnabled
= "Function disabled due to enabled filtering in playlist";
37 Connection::Connection() : itsConnection(0),
38 isCommandsListEnabled(0),
39 itsMaxPlaylistLength(-1),
53 Connection::~Connection()
56 mpd_connection_free(itsConnection
);
58 mpd_stats_free(itsStats
);
60 mpd_status_free(itsOldStatus
);
62 mpd_status_free(itsCurrentStatus
);
65 bool Connection::Connect()
69 itsConnection
= mpd_connection_new(itsHost
.c_str(), itsPort
, itsTimeout
*1000 /* timeout is in ms now */);
72 if (!itsPassword
.empty())
74 itsFD
= mpd_connection_get_fd(itsConnection
);
75 supportsIdle
= isIdleEnabled
&& Version() > 13;
76 // in UpdateStatus() we compare it to itsElapsedTimer[0],
77 // and for the first time it has always evaluate to true
78 // so we need it to be zero at this point
79 itsElapsedTimer
[1] = 0;
80 return !CheckForErrors();
83 bool Connection::Connected() const
88 void Connection::Disconnect()
91 mpd_connection_free(itsConnection
);
93 mpd_stats_free(itsStats
);
95 mpd_status_free(itsOldStatus
);
97 mpd_status_free(itsCurrentStatus
);
100 itsCurrentStatus
= 0;
103 isCommandsListEnabled
= 0;
104 itsMaxPlaylistLength
= -1;
107 float Connection::Version() const
111 const unsigned *version
= mpd_connection_get_server_version(itsConnection
);
112 return version
[1] + version
[2]*0.1;
115 void Connection::SetHostname(const std::string
&host
)
117 size_t at
= host
.find("@");
118 if (at
!= std::string::npos
)
120 itsPassword
= host
.substr(0, at
);
121 itsHost
= host
.substr(at
+1);
127 bool Connection::SendPassword()
130 assert(!isCommandsListEnabled
);
131 mpd_run_password(itsConnection
, itsPassword
.c_str());
132 return !CheckForErrors();
135 void Connection::SetStatusUpdater(StatusUpdater updater
, void *data
)
137 itsUpdater
= updater
;
138 itsStatusUpdaterUserdata
= data
;
141 void Connection::SetErrorHandler(ErrorHandler handler
, void *data
)
143 itsErrorHandler
= handler
;
144 itsErrorHandlerUserdata
= data
;
147 void Connection::GoIdle()
149 if (supportsIdle
&& !isIdle
&& mpd_send_idle(itsConnection
))
153 int Connection::GoBusy()
155 if (isIdle
&& mpd_send_noidle(itsConnection
))
158 return mpd_recv_idle(itsConnection
, 1);
163 void Connection::UpdateStatus()
173 idle_mask
= GoBusy();
178 // count local elapsed time as we don't receive
179 // this from mpd while being in idle mode
180 time(&itsElapsedTimer
[1]);
181 double diff
= difftime(itsElapsedTimer
[1], itsElapsedTimer
[0]);
182 if (diff
>= 1.0 && Mpd
.GetState() == psPlay
)
184 time(&itsElapsedTimer
[0]);
186 StatusChanges changes
;
187 changes
.ElapsedTime
= 1;
189 itsUpdater(this, changes
, itsErrorHandlerUserdata
);
201 mpd_status_free(itsOldStatus
);
203 itsOldStatus
= itsCurrentStatus
;
204 itsCurrentStatus
= 0;
206 itsCurrentStatus
= mpd_run_status(itsConnection
);
208 if (!itsMaxPlaylistLength
)
209 itsMaxPlaylistLength
= GetPlaylistLength();
211 if (CheckForErrors())
214 if (itsCurrentStatus
&& itsUpdater
)
218 // sync local elapsed time counter with mpd
219 unsigned old_elapsed
= itsElapsed
;
220 itsElapsed
= mpd_status_get_elapsed_time(itsCurrentStatus
);
221 itsChanges
.ElapsedTime
= itsElapsed
!= old_elapsed
;
222 time(&itsElapsedTimer
[0]);
225 itsElapsed
= mpd_status_get_elapsed_time(itsCurrentStatus
);
229 itsChanges
.Playlist
= 1;
230 itsChanges
.SongID
= 1;
231 itsChanges
.Database
= 1;
232 itsChanges
.DBUpdating
= 1;
233 itsChanges
.Volume
= 1;
234 itsChanges
.ElapsedTime
= 1;
235 itsChanges
.Crossfade
= 1;
236 itsChanges
.Random
= 1;
237 itsChanges
.Repeat
= 1;
238 itsChanges
.Single
= 1;
239 itsChanges
.Consume
= 1;
240 itsChanges
.PlayerState
= 1;
241 itsChanges
.StatusFlags
= 1;
242 itsChanges
.Outputs
= 1;
248 itsChanges
.Playlist
= idle_mask
& MPD_IDLE_QUEUE
;
249 itsChanges
.Database
= idle_mask
& MPD_IDLE_DATABASE
;
250 itsChanges
.DBUpdating
= idle_mask
& MPD_IDLE_UPDATE
;
251 itsChanges
.Volume
= idle_mask
& MPD_IDLE_MIXER
;
252 itsChanges
.StatusFlags
= idle_mask
& (MPD_IDLE_OPTIONS
| MPD_IDLE_UPDATE
);
253 itsChanges
.Outputs
= idle_mask
& MPD_IDLE_OUTPUT
;
257 itsChanges
.Playlist
= mpd_status_get_queue_version(itsOldStatus
)
258 != mpd_status_get_queue_version(itsCurrentStatus
);
260 itsChanges
.ElapsedTime
= mpd_status_get_elapsed_time(itsOldStatus
)
261 != mpd_status_get_elapsed_time(itsCurrentStatus
);
263 itsChanges
.Database
= mpd_status_get_update_id(itsOldStatus
)
264 && !mpd_status_get_update_id(itsCurrentStatus
);
266 itsChanges
.DBUpdating
= mpd_status_get_update_id(itsOldStatus
)
267 != mpd_status_get_update_id(itsCurrentStatus
);
269 itsChanges
.Volume
= mpd_status_get_volume(itsOldStatus
)
270 != mpd_status_get_volume(itsCurrentStatus
);
272 itsChanges
.StatusFlags
= itsChanges
.Repeat
275 || itsChanges
.Consume
276 || itsChanges
.Crossfade
277 || itsChanges
.DBUpdating
;
279 // there is no way to determine if the output has changed or not
280 // from mpd status, it's possible only with idle notifications
281 itsChanges
.Outputs
= 0;
284 itsChanges
.SongID
= mpd_status_get_song_id(itsOldStatus
)
285 != mpd_status_get_song_id(itsCurrentStatus
);
287 itsChanges
.Crossfade
= mpd_status_get_crossfade(itsOldStatus
)
288 != mpd_status_get_crossfade(itsCurrentStatus
);
290 itsChanges
.Random
= mpd_status_get_random(itsOldStatus
)
291 != mpd_status_get_random(itsCurrentStatus
);
293 itsChanges
.Repeat
= mpd_status_get_repeat(itsOldStatus
)
294 != mpd_status_get_repeat(itsCurrentStatus
);
296 itsChanges
.Single
= mpd_status_get_single(itsOldStatus
)
297 != mpd_status_get_single(itsCurrentStatus
);
299 itsChanges
.Consume
= mpd_status_get_consume(itsOldStatus
)
300 != mpd_status_get_consume(itsCurrentStatus
);
302 itsChanges
.PlayerState
= mpd_status_get_state(itsOldStatus
)
303 != mpd_status_get_state(itsCurrentStatus
);
305 itsUpdater(this, itsChanges
, itsErrorHandlerUserdata
);
306 // status updater could invoke mpd commands that
307 // could fail se we need to check for errors
310 // below conditionals are a hack to workaround mpd bug 2608/2612
311 // by fetching another status with correct values after a while
312 if (!((idle_mask
& MPD_IDLE_PLAYER
) && !itsChanges
.PlayerState
))
314 //else if (supportsIdle && !isIdle)
315 // OrderDataFetching();
322 void Connection::UpdateStats()
326 assert(!isCommandsListEnabled
);
329 mpd_stats_free(itsStats
);
330 itsStats
= mpd_run_stats(itsConnection
);
334 bool Connection::UpdateDirectory(const std::string
&path
)
338 if (!isCommandsListEnabled
)
341 bool success
= mpd_run_update(itsConnection
, path
.c_str());
342 if (!supportsIdle
&& success
)
349 return mpd_send_update(itsConnection
, path
.c_str());
354 void Connection::Play()
358 if (!isCommandsListEnabled
)
361 mpd_run_play(itsConnection
);
366 mpd_send_play(itsConnection
);
370 void Connection::Play(int pos
)
374 if (!isCommandsListEnabled
)
377 mpd_run_play_pos(itsConnection
, pos
);
382 mpd_send_play_pos(itsConnection
, pos
);
386 void Connection::PlayID(int id
)
390 if (!isCommandsListEnabled
)
393 mpd_run_play_id(itsConnection
, id
);
398 mpd_send_play_id(itsConnection
, id
);
402 void Connection::Pause(bool state
)
406 if (!isCommandsListEnabled
)
409 mpd_run_pause(itsConnection
, state
);
414 mpd_send_pause(itsConnection
, state
);
418 void Connection::Toggle()
422 if (!isCommandsListEnabled
)
425 mpd_run_toggle_pause(itsConnection
);;
430 mpd_send_toggle_pause(itsConnection
);
434 void Connection::Stop()
438 if (!isCommandsListEnabled
)
441 mpd_run_stop(itsConnection
);
446 mpd_send_stop(itsConnection
);
450 void Connection::Next()
454 if (!isCommandsListEnabled
)
457 mpd_run_next(itsConnection
);
462 mpd_send_next(itsConnection
);
466 void Connection::Prev()
470 if (!isCommandsListEnabled
)
473 mpd_run_previous(itsConnection
);
478 mpd_send_previous(itsConnection
);
482 void Connection::Move(unsigned from
, unsigned to
)
486 if (!isCommandsListEnabled
)
489 mpd_run_move(itsConnection
, from
, to
);
494 mpd_send_move(itsConnection
, from
, to
);
498 void Connection::Swap(unsigned from
, unsigned to
)
502 if (!isCommandsListEnabled
)
505 mpd_run_swap(itsConnection
, from
, to
);
510 mpd_send_swap(itsConnection
, from
, to
);
514 void Connection::Seek(unsigned where
)
518 if (!isCommandsListEnabled
)
521 mpd_run_seek_pos(itsConnection
, Mpd
.GetCurrentSongPos(), where
);
526 mpd_send_seek_pos(itsConnection
, Mpd
.GetCurrentSongPos(), where
);
530 void Connection::Shuffle()
534 if (!isCommandsListEnabled
)
537 mpd_run_shuffle(itsConnection
);
542 mpd_send_shuffle(itsConnection
);
546 void Connection::ClearPlaylist()
550 if (!isCommandsListEnabled
)
553 mpd_run_clear(itsConnection
);
558 mpd_send_clear(itsConnection
);
562 void Connection::ClearPlaylist(const std::string
&playlist
)
566 if (!isCommandsListEnabled
)
569 mpd_run_playlist_clear(itsConnection
, playlist
.c_str());
573 mpd_send_playlist_clear(itsConnection
, playlist
.c_str());
578 void Connection::AddToPlaylist(const std::string
&path
, const Song
&s
)
581 AddToPlaylist(path
, s
.GetFile());
584 void Connection::AddToPlaylist(const std::string
&path
, const std::string
&file
)
588 if (!isCommandsListEnabled
)
591 mpd_run_playlist_add(itsConnection
, path
.c_str(), file
.c_str());
596 mpd_send_playlist_add(itsConnection
, path
.c_str(), file
.c_str());
600 void Connection::Move(const std::string
&path
, int from
, int to
)
604 if (!isCommandsListEnabled
)
608 mpd_send_playlist_move(itsConnection
, path
.c_str(), from
, to
);
609 if (!isCommandsListEnabled
)
610 mpd_response_finish(itsConnection
);
613 bool Connection::Rename(const std::string
&from
, const std::string
&to
)
617 if (!isCommandsListEnabled
)
620 return mpd_run_rename(itsConnection
, from
.c_str(), to
.c_str());
625 return mpd_send_rename(itsConnection
, from
.c_str(), to
.c_str());
629 void Connection::GetPlaylistChanges(unsigned version
, SongList
&v
)
633 assert(!isCommandsListEnabled
);
635 v
.reserve(GetPlaylistLength());
637 mpd_send_queue_changes_meta(itsConnection
, version
);
638 while (mpd_song
*s
= mpd_recv_song(itsConnection
))
639 v
.push_back(new Song(s
, 1));
640 mpd_response_finish(itsConnection
);
644 Song
Connection::GetSong(const std::string
&path
)
648 assert(!isCommandsListEnabled
);
650 mpd_send_list_all_meta(itsConnection
, path
.c_str());
651 mpd_song
*s
= mpd_recv_song(itsConnection
);
652 mpd_response_finish(itsConnection
);
657 int Connection::GetCurrentSongPos() const
659 return itsCurrentStatus
&& isPlaying() ? mpd_status_get_song_pos(itsCurrentStatus
) : -1;
662 Song
Connection::GetCurrentSong()
664 assert(!isCommandsListEnabled
);
666 Song result
= Song(itsConnection
&& isPlaying() ? mpd_run_current_song(itsConnection
) : 0);
671 void Connection::GetPlaylistContent(const std::string
&path
, SongList
&v
)
675 assert(!isCommandsListEnabled
);
677 mpd_send_list_playlist_meta(itsConnection
, path
.c_str());
678 while (mpd_song
*s
= mpd_recv_song(itsConnection
))
679 v
.push_back(new Song(s
));
680 mpd_response_finish(itsConnection
);
684 void Connection::SetRepeat(bool mode
)
688 if (!isCommandsListEnabled
)
691 mpd_run_repeat(itsConnection
, mode
);
696 mpd_send_repeat(itsConnection
, mode
);
700 void Connection::SetRandom(bool mode
)
704 if (!isCommandsListEnabled
)
707 mpd_run_random(itsConnection
, mode
);
712 mpd_send_random(itsConnection
, mode
);
716 void Connection::SetSingle(bool mode
)
720 if (!isCommandsListEnabled
)
723 mpd_run_single(itsConnection
, mode
);
728 mpd_send_single(itsConnection
, mode
);
732 void Connection::SetConsume(bool mode
)
736 if (!isCommandsListEnabled
)
739 mpd_run_consume(itsConnection
, mode
);
744 mpd_send_consume(itsConnection
, mode
);
748 void Connection::SetVolume(unsigned vol
)
750 if (!itsConnection
|| vol
> 100)
752 assert(!isCommandsListEnabled
);
754 if (mpd_run_set_volume(itsConnection
, vol
) && !supportsIdle
)
758 std::string
Connection::GetReplayGainMode()
762 assert(!isCommandsListEnabled
);
764 if (!mpd_send_command(itsConnection
, "replay_gain_status", NULL
))
767 if (mpd_pair
*pair
= mpd_recv_pair_named(itsConnection
, "replay_gain_mode"))
769 result
= pair
->value
;
771 result
[0] = toupper(result
[0]);
772 mpd_return_pair(itsConnection
, pair
);
774 mpd_response_finish(itsConnection
);
778 void Connection::SetReplayGainMode(ReplayGainMode mode
)
795 FatalError("undefined value of ReplayGainMode!");
797 if (!isCommandsListEnabled
)
801 if (!mpd_send_command(itsConnection
, "replay_gain_mode", rg_mode
, NULL
))
803 if (!isCommandsListEnabled
)
804 mpd_response_finish(itsConnection
);
807 void Connection::SetCrossfade(unsigned crossfade
)
811 if (!isCommandsListEnabled
)
814 mpd_run_crossfade(itsConnection
, crossfade
);
819 mpd_send_crossfade(itsConnection
, crossfade
);
823 int Connection::AddSong(const std::string
&path
, int pos
)
828 if (GetPlaylistLength() < itsMaxPlaylistLength
)
830 if (!isCommandsListEnabled
)
835 mpd_send_add_id(itsConnection
, path
.c_str());
837 mpd_send_add_id_to(itsConnection
, path
.c_str(), pos
);
838 if (!isCommandsListEnabled
)
840 id
= mpd_recv_song_id(itsConnection
);
841 mpd_response_finish(itsConnection
);
846 else if (itsErrorHandler
)
847 itsErrorHandler(this, MPD_SERVER_ERROR_PLAYLIST_MAX
, Message::FullPlaylist
, itsErrorHandlerUserdata
);
851 int Connection::AddSong(const Song
&s
, int pos
)
853 return !s
.Empty() ? (AddSong((!s
.isFromDB() ? "file://" : "") + (s
.Localized() ? locale_to_utf_cpy(s
.GetFile()) : s
.GetFile()), pos
)) : -1;
856 void Connection::Add(const std::string
&path
)
860 if (!isCommandsListEnabled
)
863 mpd_run_add(itsConnection
, path
.c_str());
868 mpd_send_add(itsConnection
, path
.c_str());
872 bool Connection::AddRandomSongs(size_t number
)
874 if (!itsConnection
&& !number
)
876 assert(!isCommandsListEnabled
);
881 mpd_send_list_all(itsConnection
, "/");
882 while (mpd_pair
*item
= mpd_recv_pair_named(itsConnection
, "file"))
884 files
.push_back(item
->value
);
885 mpd_return_pair(itsConnection
, item
);
887 mpd_response_finish(itsConnection
);
889 if (number
> files
.size())
892 itsErrorHandler(this, 0, "Requested number of random songs is bigger than size of your library!", itsErrorHandlerUserdata
);
898 std::random_shuffle(files
.begin(), files
.end());
900 TagList::const_iterator it
= files
.begin()+rand()%(files
.size()-number
);
901 for (size_t i
= 0; i
< number
&& it
!= files
.end(); ++i
)
903 CommitCommandsList();
908 bool Connection::Delete(unsigned pos
)
912 if (!isCommandsListEnabled
)
916 bool result
= mpd_send_delete(itsConnection
, pos
);
917 if (!isCommandsListEnabled
)
918 result
= mpd_response_finish(itsConnection
);
922 bool Connection::DeleteID(unsigned id
)
926 if (!isCommandsListEnabled
)
930 bool result
= mpd_send_delete_id(itsConnection
, id
);
931 if (!isCommandsListEnabled
)
932 result
= mpd_response_finish(itsConnection
);
936 bool Connection::Delete(const std::string
&playlist
, unsigned pos
)
940 if (!isCommandsListEnabled
)
943 return mpd_run_playlist_delete(itsConnection
, playlist
.c_str(), pos
);
948 return mpd_send_playlist_delete(itsConnection
, playlist
.c_str(), pos
);
952 void Connection::StartCommandsList()
956 assert(!isCommandsListEnabled
);
958 mpd_command_list_begin(itsConnection
, 1);
959 isCommandsListEnabled
= 1;
962 bool Connection::CommitCommandsList()
966 assert(isCommandsListEnabled
);
968 mpd_command_list_end(itsConnection
);
969 mpd_response_finish(itsConnection
);
970 if (GetPlaylistLength() == itsMaxPlaylistLength
&& itsErrorHandler
)
971 itsErrorHandler(this, MPD_SERVER_ERROR_PLAYLIST_MAX
, Message::FullPlaylist
, itsErrorHandlerUserdata
);
972 isCommandsListEnabled
= 0;
973 bool result
= !CheckForErrors();
978 bool Connection::DeletePlaylist(const std::string
&name
)
982 if (!isCommandsListEnabled
)
985 return mpd_run_rm(itsConnection
, name
.c_str());
990 return mpd_send_rm(itsConnection
, name
.c_str());
994 bool Connection::SavePlaylist(const std::string
&name
)
998 assert(!isCommandsListEnabled
);
1000 mpd_send_save(itsConnection
, name
.c_str());
1001 mpd_response_finish(itsConnection
);
1002 return !(mpd_connection_get_error(itsConnection
) == MPD_ERROR_SERVER
1003 && mpd_connection_get_server_error(itsConnection
) == MPD_SERVER_ERROR_EXIST
);
1006 void Connection::GetPlaylists(TagList
&v
)
1011 GetDirectory("/", list
);
1012 for (ItemList::const_iterator it
= list
.begin(); it
!= list
.end(); ++it
)
1013 if (it
->type
== itPlaylist
)
1014 v
.push_back(it
->name
);
1018 void Connection::GetList(TagList
&v
, mpd_tag_type type
)
1022 assert(!isCommandsListEnabled
);
1024 mpd_search_db_tags(itsConnection
, type
);
1025 mpd_search_commit(itsConnection
);
1026 while (mpd_pair
*item
= mpd_recv_pair_tag(itsConnection
, type
))
1028 if (item
->value
[0] != 0) // do not push empty item
1029 v
.push_back(item
->value
);
1030 mpd_return_pair(itsConnection
, item
);
1032 mpd_response_finish(itsConnection
);
1036 void Connection::GetAlbums(const std::string
&artist
, TagList
&v
)
1040 assert(!isCommandsListEnabled
);
1042 mpd_search_db_tags(itsConnection
, MPD_TAG_ALBUM
);
1043 if (!artist
.empty())
1044 mpd_search_add_tag_constraint(itsConnection
, MPD_OPERATOR_DEFAULT
, MPD_TAG_ARTIST
, artist
.c_str());
1045 mpd_search_commit(itsConnection
);
1046 while (mpd_pair
*item
= mpd_recv_pair_tag(itsConnection
, MPD_TAG_ALBUM
))
1048 if (item
->value
[0] != 0) // do not push empty item
1049 v
.push_back(item
->value
);
1050 mpd_return_pair(itsConnection
, item
);
1052 mpd_response_finish(itsConnection
);
1056 void Connection::StartSearch(bool exact_match
)
1059 mpd_search_db_songs(itsConnection
, exact_match
);
1062 void Connection::StartFieldSearch(mpd_tag_type item
)
1066 itsSearchedField
= item
;
1067 mpd_search_db_tags(itsConnection
, item
);
1071 void Connection::AddSearch(mpd_tag_type item
, const std::string
&str
)
1073 // mpd version < 0.14.* doesn't support empty search constraints
1074 if (Version() < 14 && str
.empty())
1077 mpd_search_add_tag_constraint(itsConnection
, MPD_OPERATOR_DEFAULT
, item
, str
.c_str());
1080 void Connection::CommitSearch(SongList
&v
)
1084 assert(!isCommandsListEnabled
);
1086 mpd_search_commit(itsConnection
);
1087 while (mpd_song
*s
= mpd_recv_song(itsConnection
))
1088 v
.push_back(new Song(s
));
1089 mpd_response_finish(itsConnection
);
1093 void Connection::CommitSearch(TagList
&v
)
1097 assert(!isCommandsListEnabled
);
1099 mpd_search_commit(itsConnection
);
1100 while (mpd_pair
*tag
= mpd_recv_pair_tag(itsConnection
, itsSearchedField
))
1102 if (tag
->value
[0] != 0) // do not push empty item
1103 v
.push_back(tag
->value
);
1104 mpd_return_pair(itsConnection
, tag
);
1106 mpd_response_finish(itsConnection
);
1110 void Connection::GetDirectory(const std::string
&path
, ItemList
&v
)
1114 assert(!isCommandsListEnabled
);
1116 mpd_send_list_meta(itsConnection
, path
.c_str());
1117 while (mpd_entity
*item
= mpd_recv_entity(itsConnection
))
1120 switch (mpd_entity_get_type(item
))
1122 case MPD_ENTITY_TYPE_DIRECTORY
:
1123 it
.name
= mpd_directory_get_path(mpd_entity_get_directory(item
));
1124 it
.type
= itDirectory
;
1126 case MPD_ENTITY_TYPE_SONG
:
1127 it
.song
= new Song(mpd_song_dup(mpd_entity_get_song(item
)));
1130 case MPD_ENTITY_TYPE_PLAYLIST
:
1131 it
.name
= mpd_playlist_get_path(mpd_entity_get_playlist(item
));
1132 it
.type
= itPlaylist
;
1140 mpd_entity_free(item
);
1142 mpd_response_finish(itsConnection
);
1146 void Connection::GetDirectoryRecursive(const std::string
&path
, SongList
&v
)
1150 assert(!isCommandsListEnabled
);
1152 mpd_send_list_all_meta(itsConnection
, path
.c_str());
1153 while (mpd_song
*s
= mpd_recv_song(itsConnection
))
1154 v
.push_back(new Song(s
));
1155 mpd_response_finish(itsConnection
);
1159 void Connection::GetSongs(const std::string
&path
, SongList
&v
)
1163 assert(!isCommandsListEnabled
);
1165 mpd_send_list_meta(itsConnection
, path
.c_str());
1166 while (mpd_song
*s
= mpd_recv_song(itsConnection
))
1167 v
.push_back(new Song(s
));
1168 mpd_response_finish(itsConnection
);
1172 void Connection::GetDirectories(const std::string
&path
, TagList
&v
)
1176 assert(!isCommandsListEnabled
);
1178 mpd_send_list_meta(itsConnection
, path
.c_str());
1179 while (mpd_directory
*dir
= mpd_recv_directory(itsConnection
))
1181 v
.push_back(mpd_directory_get_path(dir
));
1182 mpd_directory_free(dir
);
1184 mpd_response_finish(itsConnection
);
1188 void Connection::GetOutputs(OutputList
&v
)
1192 assert(!isCommandsListEnabled
);
1194 mpd_send_outputs(itsConnection
);
1195 while (mpd_output
*output
= mpd_recv_output(itsConnection
))
1197 v
.push_back(std::make_pair(mpd_output_get_name(output
), mpd_output_get_enabled(output
)));
1198 mpd_output_free(output
);
1200 mpd_response_finish(itsConnection
);
1204 bool Connection::EnableOutput(int id
)
1208 if (!isCommandsListEnabled
)
1211 return mpd_run_enable_output(itsConnection
, id
);
1216 return mpd_send_enable_output(itsConnection
, id
);
1220 bool Connection::DisableOutput(int id
)
1224 if (!isCommandsListEnabled
)
1227 return mpd_run_disable_output(itsConnection
, id
);
1232 return mpd_send_disable_output(itsConnection
, id
);
1236 void Connection::GetURLHandlers(TagList
&v
)
1240 assert(!isCommandsListEnabled
);
1242 mpd_send_list_url_schemes(itsConnection
);
1243 while (mpd_pair
*handler
= mpd_recv_pair_named(itsConnection
, "handler"))
1245 v
.push_back(handler
->value
);
1246 mpd_return_pair(itsConnection
, handler
);
1248 mpd_response_finish(itsConnection
);
1252 void Connection::GetTagTypes(TagList
&v
)
1256 assert(!isCommandsListEnabled
);
1258 mpd_send_list_tag_types(itsConnection
);
1259 while (mpd_pair
*tag_type
= mpd_recv_pair_named(itsConnection
, "tagtype"))
1261 v
.push_back(tag_type
->value
);
1262 mpd_return_pair(itsConnection
, tag_type
);
1264 mpd_response_finish(itsConnection
);
1268 int Connection::CheckForErrors()
1271 if ((error_code
= mpd_connection_get_error(itsConnection
)) != MPD_ERROR_SUCCESS
)
1273 itsErrorMessage
= mpd_connection_get_error_message(itsConnection
);
1274 if (error_code
== MPD_ERROR_SERVER
)
1276 // this is to avoid setting too small max size as we check it before fetching current status
1277 // setting real max playlist length is in UpdateStatus()
1278 error_code
= mpd_connection_get_server_error(itsConnection
);
1279 if (error_code
== MPD_SERVER_ERROR_PLAYLIST_MAX
&& itsMaxPlaylistLength
== size_t(-1))
1280 itsMaxPlaylistLength
= 0;
1282 if (!mpd_connection_clear_error(itsConnection
))
1284 if (itsErrorHandler
)
1285 itsErrorHandler(this, error_code
, itsErrorMessage
.c_str(), itsErrorHandlerUserdata
);
1290 void MPD::FreeSongList(SongList
&l
)
1292 for (SongList::iterator i
= l
.begin(); i
!= l
.end(); ++i
)
1297 void MPD::FreeItemList(ItemList
&l
)
1299 for (ItemList::iterator i
= l
.begin(); i
!= l
.end(); ++i
)