2 * Copyright (C) 2005-2013 Team XBMC
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, or (at your option)
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 XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #include "settings/AdvancedSettings.h"
23 #include "utils/StringUtils.h"
24 #include "utils/XMLUtils.h"
25 #include "utils/MathUtils.h"
29 using namespace MUSIC_INFO;
31 CAlbum::CAlbum(const CFileItem& item)
34 const CMusicInfoTag& tag = *item.GetMusicInfoTag();
36 tag.GetReleaseDate(stTime);
37 strAlbum = tag.GetAlbum();
38 strMusicBrainzAlbumID = tag.GetMusicBrainzAlbumID();
39 genre = tag.GetGenre();
40 artist = tag.GetAlbumArtist();
41 bool hasMusicBrainzAlbumArtist = !tag.GetMusicBrainzAlbumArtistID().empty();
42 const vector<string>& artists = hasMusicBrainzAlbumArtist ? tag.GetMusicBrainzAlbumArtistID() : tag.GetAlbumArtist();
43 for (vector<string>::const_iterator it = artists.begin(); it != artists.end(); ++it)
45 CStdString artistName = hasMusicBrainzAlbumArtist && !artist.empty() ? artist[0] : *it;
46 CStdString artistId = hasMusicBrainzAlbumArtist ? *it : StringUtils::EmptyString;
47 CStdString strJoinPhrase = (it == --artists.end() ? "" : g_advancedSettings.m_musicItemSeparator);
48 CArtistCredit artistCredit(artistName, artistId, strJoinPhrase);
49 artistCredits.push_back(artistCredit);
52 bCompilation = tag.GetCompilation();
56 CStdString CAlbum::GetArtistString() const
58 return StringUtils::Join(artist, g_advancedSettings.m_musicItemSeparator);
61 CStdString CAlbum::GetGenreString() const
63 return StringUtils::Join(genre, g_advancedSettings.m_musicItemSeparator);
66 bool CAlbum::operator<(const CAlbum &a) const
68 if (strMusicBrainzAlbumID.empty() && a.strMusicBrainzAlbumID.empty())
70 if (strAlbum < a.strAlbum) return true;
71 if (strAlbum > a.strAlbum) return false;
73 // This will do an std::vector compare (i.e. item by item)
74 if (artist < a.artist) return true;
75 if (artist > a.artist) return false;
79 if (strMusicBrainzAlbumID < a.strMusicBrainzAlbumID) return true;
80 if (strMusicBrainzAlbumID > a.strMusicBrainzAlbumID) return false;
84 bool CAlbum::Load(const TiXmlElement *album, bool append, bool prioritise)
86 if (!album) return false;
90 XMLUtils::GetString(album, "title", strAlbum);
91 XMLUtils::GetString(album, "musicBrainzAlbumID", strMusicBrainzAlbumID);
93 XMLUtils::GetStringArray(album, "artist", artist, prioritise, g_advancedSettings.m_musicItemSeparator);
94 XMLUtils::GetStringArray(album, "genre", genre, prioritise, g_advancedSettings.m_musicItemSeparator);
95 XMLUtils::GetStringArray(album, "style", styles, prioritise, g_advancedSettings.m_musicItemSeparator);
96 XMLUtils::GetStringArray(album, "mood", moods, prioritise, g_advancedSettings.m_musicItemSeparator);
97 XMLUtils::GetStringArray(album, "theme", themes, prioritise, g_advancedSettings.m_musicItemSeparator);
98 XMLUtils::GetBoolean(album, "compilation", bCompilation);
100 XMLUtils::GetString(album,"review",strReview);
101 XMLUtils::GetString(album,"releasedate",m_strDateOfRelease);
102 XMLUtils::GetString(album,"label",strLabel);
103 XMLUtils::GetString(album,"type",strType);
105 XMLUtils::GetInt(album,"year",iYear);
106 const TiXmlElement* rElement = album->FirstChildElement("rating");
110 float max_rating = 5;
111 XMLUtils::GetFloat(album, "rating", rating);
112 if (rElement->QueryFloatAttribute("max", &max_rating) == TIXML_SUCCESS && max_rating>=1)
113 rating *= (5.f / max_rating); // Normalise the Rating to between 0 and 5
116 iRating = MathUtils::round_int(rating);
119 size_t iThumbCount = thumbURL.m_url.size();
120 CStdString xmlAdd = thumbURL.m_xml;
121 const TiXmlElement* thumb = album->FirstChildElement("thumb");
124 thumbURL.ParseElement(thumb);
129 xmlAdd = temp+xmlAdd;
131 thumb = thumb->NextSiblingElement("thumb");
133 // prioritise thumbs from nfos
134 if (prioritise && iThumbCount && iThumbCount != thumbURL.m_url.size())
136 rotate(thumbURL.m_url.begin(),
137 thumbURL.m_url.begin()+iThumbCount,
138 thumbURL.m_url.end());
139 thumbURL.m_xml = xmlAdd;
142 const TiXmlElement* albumArtistCreditsNode = album->FirstChildElement("albumArtistCredits");
143 if (albumArtistCreditsNode)
144 artistCredits.clear();
146 while (albumArtistCreditsNode)
148 if (albumArtistCreditsNode->FirstChild())
150 CArtistCredit artistCredit;
151 XMLUtils::GetString(albumArtistCreditsNode, "artist", artistCredit.m_strArtist);
152 XMLUtils::GetString(albumArtistCreditsNode, "musicBrainzArtistID", artistCredit.m_strMusicBrainzArtistID);
153 XMLUtils::GetString(albumArtistCreditsNode, "joinphrase", artistCredit.m_strJoinPhrase);
154 XMLUtils::GetBoolean(albumArtistCreditsNode, "featuring", artistCredit.m_boolFeatured);
155 artistCredits.push_back(artistCredit);
158 albumArtistCreditsNode = albumArtistCreditsNode->NextSiblingElement("albumArtistCredits");
161 // Support old style <artist></artist> for backwards compatibility
162 // .nfo files should ideally be updated to use the artist credits structure above
163 // or removed entirely in preference for better tags (MusicBrainz?)
164 if (artistCredits.empty() && !artist.empty())
166 for (vector<string>::const_iterator it = artist.begin(); it != artist.end(); ++it)
168 CArtistCredit artistCredit(*it, StringUtils::EmptyString,
169 it == --artist.end() ? StringUtils::EmptyString : g_advancedSettings.m_musicItemSeparator);
170 artistCredits.push_back(artistCredit);
174 const TiXmlElement* node = album->FirstChildElement("track");
176 songs.clear(); // this means that the tracks can't be spread over separate pages
177 // but this is probably a reasonable limitation
178 bool bIncrement = false;
181 if (node->FirstChild())
185 const TiXmlElement* songArtistCreditsNode = node->FirstChildElement("songArtistCredits");
186 if (songArtistCreditsNode)
187 song.artistCredits.clear();
189 while (songArtistCreditsNode)
191 if (songArtistCreditsNode->FirstChild())
193 CArtistCredit artistCredit;
194 XMLUtils::GetString(songArtistCreditsNode, "artist", artistCredit.m_strArtist);
195 XMLUtils::GetString(songArtistCreditsNode, "musicBrainzArtistID", artistCredit.m_strMusicBrainzArtistID);
196 XMLUtils::GetString(songArtistCreditsNode, "joinphrase", artistCredit.m_strJoinPhrase);
197 XMLUtils::GetBoolean(songArtistCreditsNode, "featuring", artistCredit.m_boolFeatured);
198 song.artistCredits.push_back(artistCredit);
201 songArtistCreditsNode = songArtistCreditsNode->NextSiblingElement("albumArtistCredits");
204 XMLUtils::GetString(node, "musicBrainzTrackID", song.strMusicBrainzTrackID);
205 XMLUtils::GetInt(node, "position", song.iTrack);
207 if (song.iTrack == 0)
210 XMLUtils::GetString(node,"title",song.strTitle);
212 XMLUtils::GetString(node,"duration",strDur);
213 song.iDuration = StringUtils::TimeStringToSeconds(strDur);
216 song.iTrack = song.iTrack + 1;
218 songs.push_back(song);
220 node = node->NextSiblingElement("track");
226 bool CAlbum::Save(TiXmlNode *node, const CStdString &tag, const CStdString& strPath)
228 if (!node) return false;
230 // we start with a <tag> tag
231 TiXmlElement albumElement(tag.c_str());
232 TiXmlNode *album = node->InsertEndChild(albumElement);
234 if (!album) return false;
236 XMLUtils::SetString(album, "title", strAlbum);
237 XMLUtils::SetString(album, "musicBrainzAlbumID", strMusicBrainzAlbumID);
238 XMLUtils::SetStringArray(album, "artist", artist);
239 XMLUtils::SetStringArray(album, "genre", genre);
240 XMLUtils::SetStringArray(album, "style", styles);
241 XMLUtils::SetStringArray(album, "mood", moods);
242 XMLUtils::SetStringArray(album, "theme", themes);
243 XMLUtils::SetBoolean(album, "compilation", bCompilation);
245 XMLUtils::SetString(album, "review", strReview);
246 XMLUtils::SetString(album, "type", strType);
247 XMLUtils::SetString(album, "releasedate", m_strDateOfRelease);
248 XMLUtils::SetString(album, "label", strLabel);
249 XMLUtils::SetString(album, "type", strType);
250 if (!thumbURL.m_xml.empty())
253 doc.Parse(thumbURL.m_xml);
254 const TiXmlNode* thumb = doc.FirstChild("thumb");
257 album->InsertEndChild(*thumb);
258 thumb = thumb->NextSibling("thumb");
261 XMLUtils::SetString(album, "path", strPath);
263 XMLUtils::SetInt(album, "rating", iRating);
264 XMLUtils::SetInt(album, "year", iYear);
266 for( VECARTISTCREDITS::const_iterator artistCredit = artistCredits.begin();artistCredit != artistCredits.end();++artistCredit)
268 // add an <albumArtistCredits> tag
269 TiXmlElement albumArtistCreditsElement("albumArtistCredits");
270 TiXmlNode *albumArtistCreditsNode = album->InsertEndChild(albumArtistCreditsElement);
271 XMLUtils::SetString(albumArtistCreditsNode, "artist", artistCredit->m_strArtist);
272 XMLUtils::SetString(albumArtistCreditsNode, "musicBrainzArtistID", artistCredit->m_strMusicBrainzArtistID);
273 XMLUtils::SetString(albumArtistCreditsNode, "joinphrase", artistCredit->m_strJoinPhrase);
274 XMLUtils::SetString(albumArtistCreditsNode, "featuring", artistCredit->GetArtist());
277 for( VECSONGS::const_iterator song = songs.begin(); song != songs.end(); ++song)
280 TiXmlElement cast("track");
281 TiXmlNode *node = album->InsertEndChild(cast);
282 for( VECARTISTCREDITS::const_iterator artistCredit = song->artistCredits.begin(); artistCredit != song->artistCredits.end(); ++artistCredit)
284 // add an <albumArtistCredits> tag
285 TiXmlElement songArtistCreditsElement("songArtistCredits");
286 TiXmlNode *songArtistCreditsNode = node->InsertEndChild(songArtistCreditsElement);
287 XMLUtils::SetString(songArtistCreditsNode, "artist", artistCredit->m_strArtist);
288 XMLUtils::SetString(songArtistCreditsNode, "musicBrainzArtistID", artistCredit->m_strMusicBrainzArtistID);
289 XMLUtils::SetString(songArtistCreditsNode, "joinphrase", artistCredit->m_strJoinPhrase);
290 XMLUtils::SetString(songArtistCreditsNode, "featuring", artistCredit->GetArtist());
292 XMLUtils::SetString(node, "musicBrainzTrackID", song->strMusicBrainzTrackID);
293 XMLUtils::SetString(node, "title", song->strTitle);
294 XMLUtils::SetInt(node, "position", song->iTrack);
295 XMLUtils::SetString(node, "duration", StringUtils::SecondsToTimeString(song->iDuration));