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 ***************************************************************************/
23 #include <boost/format.hpp>
24 #include <boost/functional/hash.hpp>
25 #include <boost/lexical_cast.hpp>
29 #include "curses/window.h"
31 #include "utility/type_conversions.h"
32 #include "utility/wide_string.h"
36 size_t calc_hash(const char *s
, size_t seed
= 0)
38 for (; *s
!= '\0'; ++s
)
39 boost::hash_combine(seed
, *s
);
47 std::string
Song::TagsSeparator
= " | ";
49 bool Song::ShowDuplicateTags
= true;
51 std::string
Song::get(mpd_tag_type type
, unsigned idx
) const
54 const char *tag
= mpd_song_get_tag(m_song
.get(), type
, idx
);
60 Song::Song(mpd_song
*s
)
63 m_song
= std::shared_ptr
<mpd_song
>(s
, mpd_song_free
);
64 m_hash
= calc_hash(mpd_song_get_uri(s
));
67 std::string
Song::getURI(unsigned idx
) const
73 return mpd_song_get_uri(m_song
.get());
76 std::string
Song::getName(unsigned idx
) const
79 mpd_song
*s
= m_song
.get();
80 const char *res
= mpd_song_get_tag(s
, MPD_TAG_NAME
, idx
);
85 const char *uri
= mpd_song_get_uri(s
);
86 const char *name
= strrchr(uri
, '/');
93 std::string
Song::getDirectory(unsigned idx
) const
96 if (idx
> 0 || isStream())
98 const char *uri
= mpd_song_get_uri(m_song
.get());
99 const char *name
= strrchr(uri
, '/');
101 return std::string(uri
, name
-uri
);
106 std::string
Song::getArtist(unsigned idx
) const
109 return get(MPD_TAG_ARTIST
, idx
);
112 std::string
Song::getTitle(unsigned idx
) const
115 return get(MPD_TAG_TITLE
, idx
);
118 std::string
Song::getAlbum(unsigned idx
) const
121 return get(MPD_TAG_ALBUM
, idx
);
124 std::string
Song::getAlbumArtist(unsigned idx
) const
127 return get(MPD_TAG_ALBUM_ARTIST
, idx
);
130 std::string
Song::getTrack(unsigned idx
) const
133 std::string track
= get(MPD_TAG_TRACK
, idx
);
134 if ((track
.length() == 1 && track
[0] != '0')
135 || (track
.length() > 3 && track
[1] == '/'))
140 std::string
Song::getTrackNumber(unsigned idx
) const
143 std::string track
= getTrack(idx
);
144 size_t slash
= track
.find('/');
145 if (slash
!= std::string::npos
)
150 std::string
Song::getDate(unsigned idx
) const
153 return get(MPD_TAG_DATE
, idx
);
156 std::string
Song::getGenre(unsigned idx
) const
159 return get(MPD_TAG_GENRE
, idx
);
162 std::string
Song::getComposer(unsigned idx
) const
165 return get(MPD_TAG_COMPOSER
, idx
);
168 std::string
Song::getPerformer(unsigned idx
) const
171 return get(MPD_TAG_PERFORMER
, idx
);
174 std::string
Song::getDisc(unsigned idx
) const
177 return get(MPD_TAG_DISC
, idx
);
180 std::string
Song::getComment(unsigned idx
) const
183 return get(MPD_TAG_COMMENT
, idx
);
186 std::string
Song::getLength(unsigned idx
) const
191 unsigned len
= getDuration();
193 return ShowTime(len
);
198 std::string
Song::getPriority(unsigned idx
) const
203 return boost::lexical_cast
<std::string
>(getPrio());
206 std::string
MPD::Song::getTags(GetFunction f
) const
211 if (ShowDuplicateTags
)
213 for (std::string tag
; !(tag
= (this->*f
)(idx
)).empty(); ++idx
)
216 result
+= TagsSeparator
;
222 bool already_present
;
223 // This is O(n^2), but it doesn't really matter as a list of tags will have
224 // at most 2 or 3 items the vast majority of time.
225 for (std::string tag
; !(tag
= (this->*f
)(idx
)).empty(); ++idx
)
227 already_present
= false;
228 for (unsigned i
= 0; i
< idx
; ++i
)
230 if ((this->*f
)(i
) == tag
)
232 already_present
= true;
236 if (!already_present
)
239 result
+= TagsSeparator
;
247 unsigned Song::getDuration() const
250 return mpd_song_get_duration(m_song
.get());
253 unsigned Song::getPosition() const
256 return mpd_song_get_pos(m_song
.get());
259 unsigned Song::getID() const
262 return mpd_song_get_id(m_song
.get());
265 unsigned Song::getPrio() const
268 return mpd_song_get_prio(m_song
.get());
271 time_t Song::getMTime() const
274 return mpd_song_get_last_modified(m_song
.get());
277 bool Song::isFromDatabase() const
280 const char *uri
= mpd_song_get_uri(m_song
.get());
281 return uri
[0] != '/' || !strrchr(uri
, '/');
284 bool Song::isStream() const
287 return !strncmp(mpd_song_get_uri(m_song
.get()), "http://", 7);
290 bool Song::empty() const
292 return m_song
.get() == 0;
295 std::string
Song::ShowTime(unsigned length
)
297 int hours
= length
/3600;
298 length
-= hours
*3600;
299 int minutes
= length
/60;
300 length
-= minutes
*60;
301 int seconds
= length
;
305 result
= (boost::format("%d:%02d:%02d") % hours
% minutes
% seconds
).str();
307 result
= (boost::format("%d:%02d") % minutes
% seconds
).str();