1 /***************************************************************************
2 * Copyright (C) 2008-2016 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 ***************************************************************************/
21 #ifndef NCMPCPP_MPDPP_H
22 #define NCMPCPP_MPDPP_H
30 #include <mpd/client.h>
35 void checkConnectionErrors(mpd_connection
*conn
);
37 enum PlayerState
{ psUnknown
, psStop
, psPlay
, psPause
};
38 enum ReplayGainMode
{ rgmOff
, rgmTrack
, rgmAlbum
};
40 struct ClientError
: public std::exception
42 ClientError(mpd_error code_
, std::string msg
, bool clearable_
)
43 : m_code(code_
), m_msg(msg
), m_clearable(clearable_
) { }
44 virtual ~ClientError() noexcept
{ }
46 virtual const char *what() const noexcept
{ return m_msg
.c_str(); }
47 mpd_error
code() const { return m_code
; }
48 bool clearable() const { return m_clearable
; }
56 struct ServerError
: public std::exception
58 ServerError(mpd_server_error code_
, std::string msg
, bool clearable_
)
59 : m_code(code_
), m_msg(msg
), m_clearable(clearable_
) { }
60 virtual ~ServerError() noexcept
{ }
62 virtual const char *what() const noexcept
{ return m_msg
.c_str(); }
63 mpd_server_error
code() const { return m_code
; }
64 bool clearable() const { return m_clearable
; }
67 mpd_server_error m_code
;
74 friend struct Connection
;
76 bool empty() const { return m_stats
.get() == nullptr; }
78 unsigned artists() const { return mpd_stats_get_number_of_artists(m_stats
.get()); }
79 unsigned albums() const { return mpd_stats_get_number_of_albums(m_stats
.get()); }
80 unsigned songs() const { return mpd_stats_get_number_of_songs(m_stats
.get()); }
81 unsigned long playTime() const { return mpd_stats_get_play_time(m_stats
.get()); }
82 unsigned long uptime() const { return mpd_stats_get_uptime(m_stats
.get()); }
83 unsigned long dbUpdateTime() const { return mpd_stats_get_db_update_time(m_stats
.get()); }
84 unsigned long dbPlayTime() const { return mpd_stats_get_db_play_time(m_stats
.get()); }
87 Statistics(mpd_stats
*stats
) : m_stats(stats
, mpd_stats_free
) { }
89 std::shared_ptr
<mpd_stats
> m_stats
;
94 friend struct Connection
;
98 void clear() { m_status
.reset(); }
99 bool empty() const { return m_status
.get() == nullptr; }
101 int volume() const { return mpd_status_get_volume(m_status
.get()); }
102 bool repeat() const { return mpd_status_get_repeat(m_status
.get()); }
103 bool random() const { return mpd_status_get_random(m_status
.get()); }
104 bool single() const { return mpd_status_get_single(m_status
.get()); }
105 bool consume() const { return mpd_status_get_consume(m_status
.get()); }
106 unsigned playlistLength() const { return mpd_status_get_queue_length(m_status
.get()); }
107 unsigned playlistVersion() const { return mpd_status_get_queue_version(m_status
.get()); }
108 PlayerState
playerState() const { return PlayerState(mpd_status_get_state(m_status
.get())); }
109 unsigned crossfade() const { return mpd_status_get_crossfade(m_status
.get()); }
110 int currentSongPosition() const { return mpd_status_get_song_pos(m_status
.get()); }
111 int currentSongID() const { return mpd_status_get_song_id(m_status
.get()); }
112 int nextSongPosition() const { return mpd_status_get_next_song_pos(m_status
.get()); }
113 int nextSongID() const { return mpd_status_get_next_song_id(m_status
.get()); }
114 unsigned elapsedTime() const { return mpd_status_get_elapsed_time(m_status
.get()); }
115 unsigned totalTime() const { return mpd_status_get_total_time(m_status
.get()); }
116 unsigned kbps() const { return mpd_status_get_kbit_rate(m_status
.get()); }
117 unsigned updateID() const { return mpd_status_get_update_id(m_status
.get()); }
118 const char *error() const { return mpd_status_get_error(m_status
.get()); }
121 Status(mpd_status
*status
) : m_status(status
, mpd_status_free
) { }
123 std::shared_ptr
<mpd_status
> m_status
;
131 Directory(const mpd_directory
*directory
)
133 assert(directory
!= nullptr);
134 m_path
= mpd_directory_get_path(directory
);
135 m_last_modified
= mpd_directory_get_last_modified(directory
);
137 Directory(std::string path_
, time_t last_modified
= 0)
138 : m_path(std::move(path_
))
139 , m_last_modified(last_modified
)
142 bool operator==(const Directory
&rhs
) const
144 return m_path
== rhs
.m_path
145 && m_last_modified
== rhs
.m_last_modified
;
147 bool operator!=(const Directory
&rhs
) const
149 return !(*this == rhs
);
152 const std::string
&path() const
156 time_t lastModified() const
158 return m_last_modified
;
163 time_t m_last_modified
;
171 Playlist(const mpd_playlist
*playlist
)
173 assert(playlist
!= nullptr);
174 m_path
= mpd_playlist_get_path(playlist
);
175 m_last_modified
= mpd_playlist_get_last_modified(playlist
);
177 Playlist(std::string path_
, time_t last_modified
= 0)
178 : m_path(std::move(path_
))
179 , m_last_modified(last_modified
)
182 throw std::runtime_error("empty path");
185 bool operator==(const Playlist
&rhs
) const
187 return m_path
== rhs
.m_path
188 && m_last_modified
== rhs
.m_last_modified
;
190 bool operator!=(const Playlist
&rhs
) const
192 return !(*this == rhs
);
195 const std::string
&path() const
199 time_t lastModified() const
201 return m_last_modified
;
206 time_t m_last_modified
;
211 enum class Type
{ Directory
, Song
, Playlist
};
213 Item(mpd_entity
*entity
)
215 assert(entity
!= nullptr);
216 switch (mpd_entity_get_type(entity
))
218 case MPD_ENTITY_TYPE_DIRECTORY
:
219 m_type
= Type::Directory
;
220 m_directory
= Directory(mpd_entity_get_directory(entity
));
222 case MPD_ENTITY_TYPE_SONG
:
224 m_song
= Song(mpd_song_dup(mpd_entity_get_song(entity
)));
226 case MPD_ENTITY_TYPE_PLAYLIST
:
227 m_type
= Type::Playlist
;
228 m_playlist
= Playlist(mpd_entity_get_playlist(entity
));
231 throw std::runtime_error("unknown mpd_entity type");
233 mpd_entity_free(entity
);
235 Item(Directory directory_
)
236 : m_type(Type::Directory
)
237 , m_directory(std::move(directory_
))
241 , m_song(std::move(song_
))
243 Item(Playlist playlist_
)
244 : m_type(Type::Playlist
)
245 , m_playlist(std::move(playlist_
))
248 bool operator==(const Item
&rhs
) const
250 return m_directory
== rhs
.m_directory
251 && m_song
== rhs
.m_song
252 && m_playlist
== rhs
.m_playlist
;
254 bool operator!=(const Item
&rhs
) const
256 return !(*this == rhs
);
264 Directory
&directory()
266 return const_cast<Directory
&>(
267 static_cast<const Item
&>(*this).directory());
271 return const_cast<Song
&>(
272 static_cast<const Item
&>(*this).song());
276 return const_cast<Playlist
&>(
277 static_cast<const Item
&>(*this).playlist());
280 const Directory
&directory() const
282 assert(m_type
== Type::Directory
);
285 const Song
&song() const
287 assert(m_type
== Type::Song
);
290 const Playlist
&playlist() const
292 assert(m_type
== Type::Playlist
);
298 Directory m_directory
;
306 Output(mpd_output
*output
)
307 : m_output(output
, mpd_output_free
)
310 bool operator==(const Output
&rhs
) const
312 if (empty() && rhs
.empty())
314 else if (!empty() && !rhs
.empty())
315 return id() == rhs
.id()
316 && strcmp(name(), rhs
.name()) == 0
317 && enabled() == rhs
.enabled();
321 bool operator!=(const Output
&rhs
) const
323 return !(*this == rhs
);
328 assert(m_output
.get() != nullptr);
329 return mpd_output_get_id(m_output
.get());
331 const char *name() const
333 assert(m_output
.get() != nullptr);
334 return mpd_output_get_name(m_output
.get());
338 assert(m_output
.get() != nullptr);
339 return mpd_output_get_enabled(m_output
.get());
342 bool empty() const { return m_output
.get() == nullptr; }
345 std::shared_ptr
<mpd_output
> m_output
;
348 template <typename ObjectT
>
349 struct Iterator
: std::iterator
<std::input_iterator_tag
, ObjectT
>
351 // shared state of the iterator
356 typedef std::function
<bool(State
&)> Fetcher
;
358 State(mpd_connection
*connection_
, Fetcher fetcher
)
359 : m_connection(connection_
)
362 assert(m_connection
!= nullptr);
363 assert(m_fetcher
!= nullptr);
367 mpd_response_finish(m_connection
);
370 mpd_connection
*connection() const
375 void setObject(ObjectT object
)
378 *m_object
= std::move(object
);
380 m_object
.reset(new ObjectT(std::move(object
)));
384 bool operator==(const State
&rhs
) const
386 return m_connection
== rhs
.m_connection
387 && m_object
== m_object
;
389 bool operator!=(const State
&rhs
) const
391 return !(*this == rhs
);
396 return m_fetcher(*this);
398 ObjectT
&getObject() const
402 bool hasObject() const
404 return m_object
.get() != nullptr;
407 mpd_connection
*m_connection
;
409 std::unique_ptr
<ObjectT
> m_object
;
415 Iterator(mpd_connection
*connection
, typename
State::Fetcher fetcher
)
416 : m_state(std::make_shared
<State
>(connection
, std::move(fetcher
)))
418 // get the first element
424 checkConnectionErrors(m_state
->connection());
430 // check errors and change the iterator into end iterator
431 checkConnectionErrors(m_state
->connection());
435 ObjectT
&operator*() const
438 throw std::runtime_error("no object associated with the iterator");
439 assert(m_state
->hasObject());
440 return m_state
->getObject();
442 ObjectT
*operator->() const
447 Iterator
&operator++()
450 if (!m_state
->fetch())
454 Iterator
operator++(int)
461 bool operator==(const Iterator
&rhs
) const
463 return m_state
== rhs
.m_state
;
465 bool operator!=(const Iterator
&rhs
) const
467 return !(*this == rhs
);
471 std::shared_ptr
<State
> m_state
;
474 typedef Iterator
<Directory
> DirectoryIterator
;
475 typedef Iterator
<Item
> ItemIterator
;
476 typedef Iterator
<Output
> OutputIterator
;
477 typedef Iterator
<Playlist
> PlaylistIterator
;
478 typedef Iterator
<Song
> SongIterator
;
479 typedef Iterator
<std::string
> StringIterator
;
486 bool Connected() const;
489 const std::string
&GetHostname() { return m_host
; }
490 int GetPort() { return m_port
; }
492 unsigned Version() const;
494 int GetFD() const { return m_fd
; }
496 void SetHostname(const std::string
&);
497 void SetPort(int port
) { m_port
= port
; }
498 void SetTimeout(int timeout
) { m_timeout
= timeout
; }
499 void SetPassword(const std::string
&password
) { m_password
= password
; }
502 Statistics
getStatistics();
505 void UpdateDirectory(const std::string
&);
515 void Move(unsigned int from
, unsigned int to
);
516 void Swap(unsigned, unsigned);
517 void Seek(unsigned int pos
, unsigned int where
);
519 void ShuffleRange(unsigned start
, unsigned end
);
520 void ClearMainPlaylist();
522 SongIterator
GetPlaylistChanges(unsigned);
524 Song
GetCurrentSong();
525 Song
GetSong(const std::string
&);
526 SongIterator
GetPlaylistContent(const std::string
&name
);
527 SongIterator
GetPlaylistContentNoInfo(const std::string
&name
);
529 StringIterator
GetSupportedExtensions();
531 void SetRepeat(bool);
532 void SetRandom(bool);
533 void SetSingle(bool);
534 void SetConsume(bool);
535 void SetCrossfade(unsigned);
536 void SetVolume(unsigned int vol
);
538 std::string
GetReplayGainMode();
539 void SetReplayGainMode(ReplayGainMode
);
541 void SetPriority(const MPD::Song
&s
, int prio
);
543 int AddSong(const std::string
&, int = -1); // returns id of added song
544 int AddSong(const Song
&, int = -1); // returns id of added song
545 bool AddRandomTag(mpd_tag_type
, size_t, std::mt19937
&rng
);
546 bool AddRandomSongs(size_t number
, std::mt19937
&rng
);
547 void Add(const std::string
&path
);
548 void Delete(unsigned int pos
);
549 void PlaylistDelete(const std::string
&playlist
, unsigned int pos
);
550 void StartCommandsList();
551 void CommitCommandsList();
553 void DeletePlaylist(const std::string
&name
);
554 void LoadPlaylist(const std::string
&name
);
555 void SavePlaylist(const std::string
&);
556 void ClearPlaylist(const std::string
&playlist
);
557 void AddToPlaylist(const std::string
&, const Song
&);
558 void AddToPlaylist(const std::string
&, const std::string
&);
559 void PlaylistMove(const std::string
&path
, int from
, int to
);
560 void Rename(const std::string
&from
, const std::string
&to
);
562 void StartSearch(bool);
563 void StartFieldSearch(mpd_tag_type
);
564 void AddSearch(mpd_tag_type item
, const std::string
&str
) const;
565 void AddSearchAny(const std::string
&str
) const;
566 void AddSearchURI(const std::string
&str
) const;
567 SongIterator
CommitSearchSongs();
569 PlaylistIterator
GetPlaylists();
570 StringIterator
GetList(mpd_tag_type type
);
571 ItemIterator
GetDirectory(const std::string
&directory
);
572 SongIterator
GetDirectoryRecursive(const std::string
&directory
);
573 SongIterator
GetSongs(const std::string
&directory
);
574 DirectoryIterator
GetDirectories(const std::string
&directory
);
576 OutputIterator
GetOutputs();
577 void EnableOutput(int id
);
578 void DisableOutput(int id
);
580 StringIterator
GetURLHandlers();
581 StringIterator
GetTagTypes();
587 struct ConnectionDeleter
{
588 void operator()(mpd_connection
*connection
) {
589 mpd_connection_free(connection
);
593 void checkConnection() const;
595 void prechecksNoCommandsList();
596 void checkErrors() const;
598 std::unique_ptr
<mpd_connection
, ConnectionDeleter
> m_connection
;
599 bool m_command_list_active
;
607 std::string m_password
;
612 extern MPD::Connection Mpd
;
614 #endif // NCMPCPP_MPDPP_H