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 ***************************************************************************/
37 unsigned calc_hash(const char *p
)
41 hash
= (hash
<< 5) + hash
+ *p
++;
46 MPD::Song::Song(mpd_song
*s
, bool copy_ptr
) : itsSong(s
),
49 itsSlash(std::string::npos
),
58 MPD::Song::Song(const Song
&s
) : itsSong(s
.copyPtr
? s
.itsSong
: mpd_song_dup(s
.itsSong
)),
59 itsFile(s
.itsFile
? strdup(s
.itsFile
) : 0),
60 itsTags(s
.itsTags
? new TagMap(*s
.itsTags
) : 0),
61 itsNewName(s
.itsNewName
),
65 isLocalised(s
.isLocalised
)
72 mpd_song_free(itsSong
);
77 std::string
MPD::Song::GetLength() const
79 unsigned len
= mpd_song_get_duration(itsSong
);
80 return !len
? "-:--" : ShowTime(len
);
83 void MPD::Song::Localize()
88 const char *tag
, *conv_tag
;
89 conv_tag
= tag
= mpd_song_get_uri(itsSong
);
90 utf_to_locale(conv_tag
, 0);
91 if (tag
!= conv_tag
) // file has been converted
96 for (unsigned t
= MPD_TAG_ARTIST
; t
<= MPD_TAG_DISC
; ++t
)
99 for (; (tag
= mpd_song_get_tag(itsSong
, mpd_tag_type(t
), pos
)); ++pos
)
102 utf_to_locale(conv_tag
, 0);
103 if (tag
!= conv_tag
) // tag has been converted
105 SetTag(mpd_tag_type(t
), pos
, conv_tag
);
111 # endif // HAVE_ICONV_H
114 void MPD::Song::Clear()
117 mpd_song_free(itsSong
);
127 itsSlash
= std::string::npos
;
133 bool MPD::Song::Empty() const
138 bool MPD::Song::isFromDB() const
140 return (MyFilename()[0] != '/') || itsSlash
== std::string::npos
;
143 bool MPD::Song::isStream() const
145 return !strncmp(MyFilename(), "http://", 7);
148 std::string
MPD::Song::GetFile() const
153 std::string
MPD::Song::GetName() const
155 std::string name
= GetTag(MPD_TAG_NAME
, 0);
158 else if (itsSlash
!= std::string::npos
)
159 return MyFilename()+itsSlash
+1;
164 std::string
MPD::Song::GetDirectory() const
168 else if (itsSlash
== std::string::npos
)
171 return std::string(MyFilename(), itsSlash
);
174 std::string
MPD::Song::GetArtist() const
176 return GetTag(MPD_TAG_ARTIST
, 0);
179 std::string
MPD::Song::GetTitle() const
181 return GetTag(MPD_TAG_TITLE
, 0);
184 std::string
MPD::Song::GetAlbum() const
186 return GetTag(MPD_TAG_ALBUM
, 0);
189 std::string
MPD::Song::GetTrack() const
191 std::string track
= GetTag(MPD_TAG_TRACK
, 0);
192 return track
.length() == 1 && track
[0] != '0' ? "0"+track
: track
;
195 std::string
MPD::Song::GetTrackNumber() const
197 std::string track
= GetTag(MPD_TAG_TRACK
, 0);
198 size_t slash
= track
.find('/');
199 if (slash
!= std::string::npos
)
201 track
= track
.substr(slash
+1);
202 return track
.length() == 1 && track
[0] != '0' ? "0"+track
: track
;
208 std::string
MPD::Song::GetDate() const
210 return GetTag(MPD_TAG_DATE
, 0);
213 std::string
MPD::Song::GetGenre() const
215 return GetTag(MPD_TAG_GENRE
, 0);
218 std::string
MPD::Song::GetComposer() const
220 return GetTag(MPD_TAG_COMPOSER
, 0);
223 std::string
MPD::Song::GetPerformer() const
225 return GetTag(MPD_TAG_PERFORMER
, 0);
228 std::string
MPD::Song::GetDisc() const
230 return GetTag(MPD_TAG_DISC
, 0);
233 std::string
MPD::Song::GetComment() const
235 return GetTag(MPD_TAG_COMMENT
, 0);
238 void MPD::Song::SetArtist(const std::string
&str
)
240 SetTag(MPD_TAG_ARTIST
, 0, str
);
243 void MPD::Song::SetTitle(const std::string
&str
)
245 SetTag(MPD_TAG_TITLE
, 0, str
);
248 void MPD::Song::SetAlbum(const std::string
&str
)
250 SetTag(MPD_TAG_ALBUM
, 0, str
);
253 void MPD::Song::SetTrack(const std::string
&str
)
255 SetTag(MPD_TAG_TRACK
, 0, str
);
258 void MPD::Song::SetTrack(unsigned track
)
260 SetTag(MPD_TAG_ARTIST
, 0, IntoStr(track
));
263 void MPD::Song::SetDate(const std::string
&str
)
265 SetTag(MPD_TAG_DATE
, 0, str
);
268 void MPD::Song::SetDate(unsigned year
)
270 SetTag(MPD_TAG_TRACK
, 0, IntoStr(year
));
273 void MPD::Song::SetGenre(const std::string
&str
)
275 SetTag(MPD_TAG_GENRE
, 0, str
);
278 void MPD::Song::SetComposer(const std::string
&str
)
280 SetTag(MPD_TAG_COMPOSER
, 0, str
);
283 void MPD::Song::SetPerformer(const std::string
&str
)
285 SetTag(MPD_TAG_PERFORMER
, 0, str
);
288 void MPD::Song::SetDisc(const std::string
&str
)
290 SetTag(MPD_TAG_DISC
, 0, str
);
293 void MPD::Song::SetComment(const std::string
&str
)
295 SetTag(MPD_TAG_COMMENT
, 0, str
);
298 void MPD::Song::SetPosition(unsigned pos
)
300 mpd_song_set_pos(itsSong
, pos
);
303 std::string
MPD::Song::ParseFormat(std::string::const_iterator
&it
, const char *escape_chars
) const
306 bool has_some_tags
= 0;
307 MPD::Song::GetFunction get
= 0;
312 std::string tags
= ParseFormat(it
, escape_chars
);
327 get
= &MPD::Song::GetLength
;
330 get
= &MPD::Song::GetDirectory
;
333 get
= &MPD::Song::GetName
;
336 get
= &MPD::Song::GetArtist
;
339 get
= &MPD::Song::GetAlbum
;
342 get
= &MPD::Song::GetDate
;
345 get
= &MPD::Song::GetTrackNumber
;
348 get
= &MPD::Song::GetTrack
;
351 get
= &MPD::Song::GetGenre
;
354 get
= &MPD::Song::GetComposer
;
357 get
= &MPD::Song::GetPerformer
;
360 get
= &MPD::Song::GetDisc
;
363 get
= &MPD::Song::GetComment
;
366 get
= &MPD::Song::GetTitle
;
369 result
+= *it
; // no break here
376 std::string tag
= (this->*get
)();
377 if (escape_chars
) // prepend format escape character to all given chars to escape
378 for (const char *ch
= escape_chars
; *ch
; ++ch
)
379 for (size_t i
= tag
.find(*ch
); i
!= std::string::npos
; i
= tag
.find(*ch
, i
+= 2))
380 tag
.replace(i
, 1, std::string(1, FormatEscapeCharacter
) + ch
);
381 if (!tag
.empty() && (get
!= &MPD::Song::GetLength
|| GetTotalLength()))
393 int brace_counter
= 0;
394 if (*it
!= '}' || !has_some_tags
)
396 for (; *it
!= '}' || brace_counter
; ++it
)
404 return ParseFormat(++it
, escape_chars
);
412 for (; *it
!= '}' || *(it
+1) == '|' || brace_counter
; ++it
)
425 std::string
MPD::Song::toString(const std::string
&format
, const char *escape_chars
) const
427 std::string::const_iterator it
= format
.begin();
428 return ParseFormat(it
, escape_chars
);
431 MPD::Song
&MPD::Song::operator=(const MPD::Song
&s
)
436 mpd_song_free(itsSong
);
439 itsSong
= s
.copyPtr
? s
.itsSong
: (s
.itsSong
? mpd_song_dup(s
.itsSong
) : 0);
440 itsFile
= s
.itsFile
? strdup(s
.itsFile
) : 0;
441 itsTags
= s
.itsTags
? new TagMap(*s
.itsTags
) : 0;
442 itsNewName
= s
.itsNewName
;
443 itsSlash
= s
.itsSlash
;
446 isLocalised
= s
.isLocalised
;
450 std::string
MPD::Song::ShowTime(int length
)
452 std::ostringstream ss
;
454 int hours
= length
/3600;
455 length
-= hours
*3600;
456 int minutes
= length
/60;
457 length
-= minutes
*60;
458 int seconds
= length
;
463 << std::setw(2) << std::setfill('0') << minutes
<< ":"
464 << std::setw(2) << std::setfill('0') << seconds
;
469 << std::setw(2) << std::setfill('0') << seconds
;
474 void MPD::Song::ValidateFormat(const std::string
&type
, const std::string
&s
)
477 for (std::string::const_iterator it
= s
.begin(); it
!= s
.end(); ++it
)
485 FatalError(type
+ ": number of opening and closing braces does not equal!");
488 void MPD::Song::SetHashAndSlash()
490 const char *filename
= MyFilename();
493 const char *tmp
= strrchr(filename
, '/');
494 itsSlash
= tmp
? tmp
-filename
: std::string::npos
;
497 itsHash
= calc_hash(filename
);
500 const char *MPD::Song::MyFilename() const
502 return itsFile
? itsFile
: mpd_song_get_uri(itsSong
);
505 void MPD::Song::SetTag(mpd_tag_type type
, unsigned pos
, const std::string
&value
)
508 itsTags
= new TagMap
;
509 (*itsTags
)[std::make_pair(type
, pos
)] = value
;
512 std::string
MPD::Song::GetTag(mpd_tag_type type
, unsigned pos
) const
516 TagMap::const_iterator it
= itsTags
->find(std::make_pair(type
, pos
));
517 if (it
!= itsTags
->end())
520 const char *tag
= mpd_song_get_tag(itsSong
, type
, pos
);
521 return tag
? tag
: "";