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/>.
21 #include "AudioLibrary.h"
22 #include "music/MusicDatabase.h"
25 #include "utils/StringUtils.h"
26 #include "utils/URIUtils.h"
27 #include "music/tags/MusicInfoTag.h"
28 #include "music/Artist.h"
29 #include "music/Album.h"
30 #include "music/Song.h"
31 #include "music/Artist.h"
32 #include "ApplicationMessenger.h"
33 #include "filesystem/Directory.h"
34 #include "filesystem/File.h"
35 #include "settings/Settings.h"
37 using namespace MUSIC_INFO;
38 using namespace JSONRPC;
39 using namespace XFILE;
41 JSONRPC_STATUS CAudioLibrary::GetArtists(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
43 CMusicDatabase musicdatabase;
44 if (!musicdatabase.Open())
48 musicUrl.FromString("musicdb://artists/");
49 int genreID = -1, albumID = -1, songID = -1;
50 const CVariant &filter = parameterObject["filter"];
51 if (filter.isMember("genreid"))
52 genreID = (int)filter["genreid"].asInteger();
53 else if (filter.isMember("genre"))
54 musicUrl.AddOption("genre", filter["genre"].asString());
55 else if (filter.isMember("albumid"))
56 albumID = (int)filter["albumid"].asInteger();
57 else if (filter.isMember("album"))
58 musicUrl.AddOption("album", filter["album"].asString());
59 else if (filter.isMember("songid"))
60 songID = (int)filter["songid"].asInteger();
61 else if (filter.isObject())
64 if (!GetXspFiltering("artists", filter, xsp))
67 musicUrl.AddOption("xsp", xsp);
70 bool albumArtistsOnly = !CSettings::Get().GetBool("musiclibrary.showcompilationartists");
71 if (parameterObject["albumartistsonly"].isBoolean())
72 albumArtistsOnly = parameterObject["albumartistsonly"].asBoolean();
74 SortDescription sorting;
75 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
76 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
80 if (!musicdatabase.GetArtistsNav(musicUrl.ToString(), items, albumArtistsOnly, genreID, albumID, songID, CDatabase::Filter(), sorting))
83 // Add "artist" to "properties" array by default
84 CVariant param = parameterObject;
85 if (!param.isMember("properties"))
86 param["properties"] = CVariant(CVariant::VariantTypeArray);
87 param["properties"].append("artist");
89 int size = items.Size();
90 if (items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
91 size = (int)items.GetProperty("total").asInteger();
92 HandleFileItemList("artistid", false, "artists", items, param, result, size, false);
96 JSONRPC_STATUS CAudioLibrary::GetArtistDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
98 int artistID = (int)parameterObject["artistid"].asInteger();
100 CMusicDbUrl musicUrl;
101 if (!musicUrl.FromString("musicdb://artists/"))
102 return InternalError;
104 CMusicDatabase musicdatabase;
105 if (!musicdatabase.Open())
106 return InternalError;
108 musicUrl.AddOption("artistid", artistID);
111 CDatabase::Filter filter;
112 if (!musicdatabase.GetArtistsByWhere(musicUrl.ToString(), filter, items) || items.Size() != 1)
113 return InvalidParams;
115 // Add "artist" to "properties" array by default
116 CVariant param = parameterObject;
117 if (!param.isMember("properties"))
118 param["properties"] = CVariant(CVariant::VariantTypeArray);
119 param["properties"].append("artist");
121 HandleFileItem("artistid", false, "artistdetails", items[0], param, param["properties"], result, false);
125 JSONRPC_STATUS CAudioLibrary::GetAlbums(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
127 CMusicDatabase musicdatabase;
128 if (!musicdatabase.Open())
129 return InternalError;
131 CMusicDbUrl musicUrl;
132 musicUrl.FromString("musicdb://albums/");
133 int artistID = -1, genreID = -1;
134 const CVariant &filter = parameterObject["filter"];
135 if (filter.isMember("artistid"))
136 artistID = (int)filter["artistid"].asInteger();
137 else if (filter.isMember("artist"))
138 musicUrl.AddOption("artist", filter["artist"].asString());
139 else if (filter.isMember("genreid"))
140 genreID = (int)filter["genreid"].asInteger();
141 else if (filter.isMember("genre"))
142 musicUrl.AddOption("genre", filter["genre"].asString());
143 else if (filter.isObject())
146 if (!GetXspFiltering("albums", filter, xsp))
147 return InvalidParams;
149 musicUrl.AddOption("xsp", xsp);
152 SortDescription sorting;
153 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
154 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
155 return InvalidParams;
158 if (!musicdatabase.GetAlbumsNav(musicUrl.ToString(), items, genreID, artistID, CDatabase::Filter(), sorting))
159 return InternalError;
161 JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
165 int size = items.Size();
166 if (items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
167 size = (int)items.GetProperty("total").asInteger();
168 HandleFileItemList("albumid", false, "albums", items, parameterObject, result, size, false);
173 JSONRPC_STATUS CAudioLibrary::GetAlbumDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
175 int albumID = (int)parameterObject["albumid"].asInteger();
177 CMusicDatabase musicdatabase;
178 if (!musicdatabase.Open())
179 return InternalError;
182 if (!musicdatabase.GetAlbumInfo(albumID, album, NULL))
183 return InvalidParams;
186 if (!musicdatabase.GetAlbumPath(albumID, path))
187 return InternalError;
189 CFileItemPtr albumItem;
190 FillAlbumItem(album, path, albumItem);
193 items.Add(albumItem);
194 JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
198 HandleFileItem("albumid", false, "albumdetails", items[0], parameterObject, parameterObject["properties"], result, false);
203 JSONRPC_STATUS CAudioLibrary::GetSongs(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
205 CMusicDatabase musicdatabase;
206 if (!musicdatabase.Open())
207 return InternalError;
209 CMusicDbUrl musicUrl;
210 musicUrl.FromString("musicdb://songs/");
211 int genreID = -1, albumID = -1, artistID = -1;
212 const CVariant &filter = parameterObject["filter"];
213 if (filter.isMember("artistid"))
214 artistID = (int)filter["artistid"].asInteger();
215 else if (filter.isMember("artist"))
216 musicUrl.AddOption("artist", filter["artist"].asString());
217 else if (filter.isMember("genreid"))
218 genreID = (int)filter["genreid"].asInteger();
219 else if (filter.isMember("genre"))
220 musicUrl.AddOption("genre", filter["genre"].asString());
221 else if (filter.isMember("albumid"))
222 albumID = (int)filter["albumid"].asInteger();
223 else if (filter.isMember("album"))
224 musicUrl.AddOption("album", filter["album"].asString());
225 else if (filter.isObject())
228 if (!GetXspFiltering("songs", filter, xsp))
229 return InvalidParams;
231 musicUrl.AddOption("xsp", xsp);
234 SortDescription sorting;
235 ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
236 if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
237 return InvalidParams;
240 if (!musicdatabase.GetSongsNav(musicUrl.ToString(), items, genreID, artistID, albumID, sorting))
241 return InternalError;
243 JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
247 int size = items.Size();
248 if (items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
249 size = (int)items.GetProperty("total").asInteger();
250 HandleFileItemList("songid", true, "songs", items, parameterObject, result, size, false);
255 JSONRPC_STATUS CAudioLibrary::GetSongDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
257 int idSong = (int)parameterObject["songid"].asInteger();
259 CMusicDatabase musicdatabase;
260 if (!musicdatabase.Open())
261 return InternalError;
264 if (!musicdatabase.GetSong(idSong, song))
265 return InvalidParams;
268 items.Add(CFileItemPtr(new CFileItem(song)));
269 JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
273 HandleFileItem("songid", false, "songdetails", items[0], parameterObject, parameterObject["properties"], result, false);
277 JSONRPC_STATUS CAudioLibrary::GetRecentlyAddedAlbums(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
279 CMusicDatabase musicdatabase;
280 if (!musicdatabase.Open())
281 return InternalError;
284 if (!musicdatabase.GetRecentlyAddedAlbums(albums))
285 return InternalError;
288 for (unsigned int index = 0; index < albums.size(); index++)
291 path.Format("musicdb://recentlyaddedalbums/%i/", albums[index].idAlbum);
294 FillAlbumItem(albums[index], path, item);
298 JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
302 HandleFileItemList("albumid", false, "albums", items, parameterObject, result);
306 JSONRPC_STATUS CAudioLibrary::GetRecentlyAddedSongs(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
308 CMusicDatabase musicdatabase;
309 if (!musicdatabase.Open())
310 return InternalError;
312 int amount = (int)parameterObject["albumlimit"].asInteger();
317 if (!musicdatabase.GetRecentlyAddedAlbumSongs("musicdb://", items, (unsigned int)amount))
318 return InternalError;
320 JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
324 HandleFileItemList("songid", true, "songs", items, parameterObject, result);
328 JSONRPC_STATUS CAudioLibrary::GetRecentlyPlayedAlbums(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
330 CMusicDatabase musicdatabase;
331 if (!musicdatabase.Open())
332 return InternalError;
335 if (!musicdatabase.GetRecentlyPlayedAlbums(albums))
336 return InternalError;
339 for (unsigned int index = 0; index < albums.size(); index++)
342 path.Format("musicdb://recentlyplayedalbums/%i/", albums[index].idAlbum);
345 FillAlbumItem(albums[index], path, item);
349 JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
353 HandleFileItemList("albumid", false, "albums", items, parameterObject, result);
357 JSONRPC_STATUS CAudioLibrary::GetRecentlyPlayedSongs(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
359 CMusicDatabase musicdatabase;
360 if (!musicdatabase.Open())
361 return InternalError;
364 if (!musicdatabase.GetRecentlyPlayedAlbumSongs("musicdb://", items))
365 return InternalError;
367 JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
371 HandleFileItemList("songid", true, "songs", items, parameterObject, result);
375 JSONRPC_STATUS CAudioLibrary::GetGenres(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
377 CMusicDatabase musicdatabase;
378 if (!musicdatabase.Open())
379 return InternalError;
382 if (!musicdatabase.GetGenresNav("musicdb://genres/", items))
383 return InternalError;
385 /* need to set strTitle in each item*/
386 for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
387 items[i]->GetMusicInfoTag()->SetTitle(items[i]->GetLabel());
389 HandleFileItemList("genreid", false, "genres", items, parameterObject, result);
393 JSONRPC_STATUS CAudioLibrary::SetArtistDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
395 int id = (int)parameterObject["artistid"].asInteger();
397 CMusicDatabase musicdatabase;
398 if (!musicdatabase.Open())
399 return InternalError;
402 if (!musicdatabase.GetArtistInfo(id, artist) || artist.idArtist <= 0)
403 return InvalidParams;
405 if (ParameterNotNull(parameterObject, "artist"))
406 artist.strArtist = parameterObject["artist"].asString();
407 if (ParameterNotNull(parameterObject, "instrument"))
408 CopyStringArray(parameterObject["instrument"], artist.instruments);
409 if (ParameterNotNull(parameterObject, "style"))
410 CopyStringArray(parameterObject["style"], artist.styles);
411 if (ParameterNotNull(parameterObject, "mood"))
412 CopyStringArray(parameterObject["mood"], artist.moods);
413 if (ParameterNotNull(parameterObject, "born"))
414 artist.strBorn = parameterObject["born"].asString();
415 if (ParameterNotNull(parameterObject, "formed"))
416 artist.strFormed = parameterObject["formed"].asString();
417 if (ParameterNotNull(parameterObject, "description"))
418 artist.strBiography = parameterObject["description"].asString();
419 if (ParameterNotNull(parameterObject, "genre"))
420 CopyStringArray(parameterObject["genre"], artist.genre);
421 if (ParameterNotNull(parameterObject, "died"))
422 artist.strDied = parameterObject["died"].asString();
423 if (ParameterNotNull(parameterObject, "disbanded"))
424 artist.strDisbanded = parameterObject["disbanded"].asString();
425 if (ParameterNotNull(parameterObject, "yearsactive"))
426 CopyStringArray(parameterObject["yearsactive"], artist.yearsActive);
428 if (musicdatabase.SetArtistInfo(id, artist) <= 0)
429 return InternalError;
431 CJSONRPCUtils::NotifyItemUpdated();
435 JSONRPC_STATUS CAudioLibrary::SetAlbumDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
437 int id = (int)parameterObject["albumid"].asInteger();
439 CMusicDatabase musicdatabase;
440 if (!musicdatabase.Open())
441 return InternalError;
445 if (!musicdatabase.GetAlbumInfo(id, album, &songs) || album.idAlbum <= 0)
446 return InvalidParams;
448 if (ParameterNotNull(parameterObject, "title"))
449 album.strAlbum = parameterObject["title"].asString();
450 if (ParameterNotNull(parameterObject, "artist"))
451 CopyStringArray(parameterObject["artist"], album.artist);
452 if (ParameterNotNull(parameterObject, "description"))
453 album.strReview = parameterObject["description"].asString();
454 if (ParameterNotNull(parameterObject, "genre"))
455 CopyStringArray(parameterObject["genre"], album.genre);
456 if (ParameterNotNull(parameterObject, "theme"))
457 CopyStringArray(parameterObject["theme"], album.themes);
458 if (ParameterNotNull(parameterObject, "mood"))
459 CopyStringArray(parameterObject["mood"], album.moods);
460 if (ParameterNotNull(parameterObject, "style"))
461 CopyStringArray(parameterObject["style"], album.styles);
462 if (ParameterNotNull(parameterObject, "type"))
463 album.strType = parameterObject["type"].asString();
464 if (ParameterNotNull(parameterObject, "albumlabel"))
465 album.strLabel = parameterObject["albumlabel"].asString();
466 if (ParameterNotNull(parameterObject, "rating"))
467 album.iRating = (int)parameterObject["rating"].asInteger();
468 if (ParameterNotNull(parameterObject, "year"))
469 album.iYear = (int)parameterObject["year"].asInteger();
471 if (musicdatabase.SetAlbumInfo(id, album, songs) <= 0)
472 return InternalError;
474 CJSONRPCUtils::NotifyItemUpdated();
478 JSONRPC_STATUS CAudioLibrary::SetSongDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
480 int id = (int)parameterObject["songid"].asInteger();
482 CMusicDatabase musicdatabase;
483 if (!musicdatabase.Open())
484 return InternalError;
487 if (!musicdatabase.GetSong(id, song) || song.idSong != id)
488 return InvalidParams;
490 if (ParameterNotNull(parameterObject, "title"))
491 song.strTitle = parameterObject["title"].asString();
492 if (ParameterNotNull(parameterObject, "artist"))
493 CopyStringArray(parameterObject["artist"], song.artist);
494 if (ParameterNotNull(parameterObject, "albumartist"))
495 CopyStringArray(parameterObject["albumartist"], song.albumArtist);
496 if (ParameterNotNull(parameterObject, "genre"))
497 CopyStringArray(parameterObject["genre"], song.genre);
498 if (ParameterNotNull(parameterObject, "year"))
499 song.iYear = (int)parameterObject["year"].asInteger();
500 if (ParameterNotNull(parameterObject, "rating"))
501 song.rating = '0' + (char)parameterObject["rating"].asInteger();
502 if (ParameterNotNull(parameterObject, "album"))
503 song.strAlbum = parameterObject["album"].asString();
504 if (ParameterNotNull(parameterObject, "track"))
505 song.iTrack = (song.iTrack & 0xffff0000) | ((int)parameterObject["track"].asInteger() & 0xffff);
506 if (ParameterNotNull(parameterObject, "disc"))
507 song.iTrack = (song.iTrack & 0xffff) | ((int)parameterObject["disc"].asInteger() << 16);
508 if (ParameterNotNull(parameterObject, "duration"))
509 song.iDuration = (int)parameterObject["duration"].asInteger();
510 if (ParameterNotNull(parameterObject, "comment"))
511 song.strComment = parameterObject["comment"].asString();
512 if (ParameterNotNull(parameterObject, "musicbrainztrackid"))
513 song.strMusicBrainzTrackID = parameterObject["musicbrainztrackid"].asString();
515 if (musicdatabase.UpdateSong(id, song.strTitle, song.strMusicBrainzTrackID, song.strFileName, song.strComment, song.strThumb, song.artist, song.genre, song.iTrack, song.iDuration, song.iYear, song.iTimesPlayed, song.iStartOffset, song.iEndOffset, song.lastPlayed, song.rating, song.iKaraokeNumber) <= 0)
516 return InternalError;
518 CJSONRPCUtils::NotifyItemUpdated();
522 JSONRPC_STATUS CAudioLibrary::Scan(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
524 std::string directory = parameterObject["directory"].asString();
526 if (directory.empty())
527 cmd = "updatelibrary(music)";
529 cmd.Format("updatelibrary(music, %s)", StringUtils::Paramify(directory).c_str());
531 CApplicationMessenger::Get().ExecBuiltIn(cmd);
535 JSONRPC_STATUS CAudioLibrary::Export(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
538 if (parameterObject["options"].isMember("path"))
539 cmd.Format("exportlibrary(music, false, %s)", StringUtils::Paramify(parameterObject["options"]["path"].asString()));
541 cmd.Format("exportlibrary(music, true, %s, %s)",
542 parameterObject["options"]["images"].asBoolean() ? "true" : "false",
543 parameterObject["options"]["overwrite"].asBoolean() ? "true" : "false");
545 CApplicationMessenger::Get().ExecBuiltIn(cmd);
549 JSONRPC_STATUS CAudioLibrary::Clean(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
551 CApplicationMessenger::Get().ExecBuiltIn("cleanlibrary(music)");
555 bool CAudioLibrary::FillFileItem(const CStdString &strFilename, CFileItemPtr &item, const CVariant ¶meterObject /* = CVariant(CVariant::VariantTypeArray) */)
557 CMusicDatabase musicdatabase;
558 if (strFilename.empty() || !musicdatabase.Open())
561 if (CDirectory::Exists(strFilename))
564 int albumid = musicdatabase.GetAlbumIdByPath(strFilename);
565 if (!musicdatabase.GetAlbumInfo(albumid, album, NULL))
568 item->SetFromAlbum(album);
572 if (GetAdditionalAlbumDetails(parameterObject, items, musicdatabase) != OK)
578 if (!musicdatabase.GetSongByFileName(strFilename, song))
581 item->SetFromSong(song);
585 if (GetAdditionalSongDetails(parameterObject, items, musicdatabase) != OK)
589 if (item->GetLabel().empty())
590 item->SetLabel(CUtil::GetTitleFromPath(strFilename, false));
591 if (item->GetLabel())
592 item->SetLabel(URIUtils::GetFileName(strFilename));
597 bool CAudioLibrary::FillFileItemList(const CVariant ¶meterObject, CFileItemList &list)
599 CMusicDatabase musicdatabase;
600 if (!musicdatabase.Open())
603 CStdString file = parameterObject["file"].asString();
604 int artistID = (int)parameterObject["artistid"].asInteger(-1);
605 int albumID = (int)parameterObject["albumid"].asInteger(-1);
606 int genreID = (int)parameterObject["genreid"].asInteger(-1);
608 bool success = false;
609 CFileItemPtr fileItem(new CFileItem());
610 if (FillFileItem(file, fileItem, parameterObject))
616 if (artistID != -1 || albumID != -1 || genreID != -1)
617 success |= musicdatabase.GetSongsNav("musicdb://songs/", list, genreID, artistID, albumID);
619 int songID = (int)parameterObject["songid"].asInteger(-1);
623 if (musicdatabase.GetSong(songID, song))
625 list.Add(CFileItemPtr(new CFileItem(song)));
632 // If we retrieved the list of songs by "artistid"
633 // we sort by album (and implicitly by track number)
635 list.Sort(SORT_METHOD_ALBUM_IGNORE_THE, SortOrderAscending);
636 // If we retrieve the list of songs by "genreid"
637 // we sort by artist (and implicitly by album and track number)
638 else if (genreID != -1)
639 list.Sort(SORT_METHOD_ARTIST_IGNORE_THE, SortOrderAscending);
640 // otherwise we sort by track number
642 list.Sort(SORT_METHOD_TRACKNUM, SortOrderAscending);
649 void CAudioLibrary::FillAlbumItem(const CAlbum &album, const CStdString &path, CFileItemPtr &item)
651 item = CFileItemPtr(new CFileItem(path, album));
654 JSONRPC_STATUS CAudioLibrary::GetAdditionalAlbumDetails(const CVariant ¶meterObject, CFileItemList &items, CMusicDatabase &musicdatabase)
656 if (!musicdatabase.Open())
657 return InternalError;
659 std::set<std::string> checkProperties;
660 checkProperties.insert("genreid");
661 checkProperties.insert("artistid");
662 std::set<std::string> additionalProperties;
663 if (!CheckForAdditionalProperties(parameterObject["properties"], checkProperties, additionalProperties))
666 for (int i = 0; i < items.Size(); i++)
668 CFileItemPtr item = items[i];
669 if (additionalProperties.find("genreid") != additionalProperties.end())
671 std::vector<int> genreids;
672 if (musicdatabase.GetGenresByAlbum(item->GetMusicInfoTag()->GetDatabaseId(), genreids))
674 CVariant genreidObj(CVariant::VariantTypeArray);
675 for (std::vector<int>::const_iterator genreid = genreids.begin(); genreid != genreids.end(); ++genreid)
676 genreidObj.push_back(*genreid);
678 item->SetProperty("genreid", genreidObj);
681 if (additionalProperties.find("artistid") != additionalProperties.end())
683 std::vector<int> artistids;
684 if (musicdatabase.GetArtistsByAlbum(item->GetMusicInfoTag()->GetDatabaseId(), true, artistids))
686 CVariant artistidObj(CVariant::VariantTypeArray);
687 for (std::vector<int>::const_iterator artistid = artistids.begin(); artistid != artistids.end(); ++artistid)
688 artistidObj.push_back(*artistid);
690 item->SetProperty("artistid", artistidObj);
698 JSONRPC_STATUS CAudioLibrary::GetAdditionalSongDetails(const CVariant ¶meterObject, CFileItemList &items, CMusicDatabase &musicdatabase)
700 if (!musicdatabase.Open())
701 return InternalError;
703 std::set<std::string> checkProperties;
704 checkProperties.insert("genreid");
705 checkProperties.insert("artistid");
706 checkProperties.insert("albumartistid");
707 std::set<std::string> additionalProperties;
708 if (!CheckForAdditionalProperties(parameterObject["properties"], checkProperties, additionalProperties))
711 for (int i = 0; i < items.Size(); i++)
713 CFileItemPtr item = items[i];
714 if (additionalProperties.find("genreid") != additionalProperties.end())
716 std::vector<int> genreids;
717 if (musicdatabase.GetGenresBySong(item->GetMusicInfoTag()->GetDatabaseId(), genreids))
719 CVariant genreidObj(CVariant::VariantTypeArray);
720 for (std::vector<int>::const_iterator genreid = genreids.begin(); genreid != genreids.end(); ++genreid)
721 genreidObj.push_back(*genreid);
723 item->SetProperty("genreid", genreidObj);
726 if (additionalProperties.find("artistid") != additionalProperties.end())
728 std::vector<int> artistids;
729 if (musicdatabase.GetArtistsBySong(item->GetMusicInfoTag()->GetDatabaseId(), true, artistids))
731 CVariant artistidObj(CVariant::VariantTypeArray);
732 for (std::vector<int>::const_iterator artistid = artistids.begin(); artistid != artistids.end(); ++artistid)
733 artistidObj.push_back(*artistid);
735 item->SetProperty("artistid", artistidObj);
738 if (additionalProperties.find("albumartistid") != additionalProperties.end() && item->GetMusicInfoTag()->GetAlbumId() > 0)
740 std::vector<int> albumartistids;
741 if (musicdatabase.GetArtistsByAlbum(item->GetMusicInfoTag()->GetAlbumId(), true, albumartistids))
743 CVariant albumartistidObj(CVariant::VariantTypeArray);
744 for (std::vector<int>::const_iterator albumartistid = albumartistids.begin(); albumartistid != albumartistids.end(); ++albumartistid)
745 albumartistidObj.push_back(*albumartistid);
747 item->SetProperty("albumartistid", albumartistidObj);
755 bool CAudioLibrary::CheckForAdditionalProperties(const CVariant &properties, const std::set<std::string> &checkProperties, std::set<std::string> &foundProperties)
757 if (!properties.isArray() || properties.empty())
760 std::set<std::string> checkingProperties = checkProperties;
761 for (CVariant::const_iterator_array itr = properties.begin_array(); itr != properties.end_array() && !checkingProperties.empty(); itr++)
763 if (!itr->isString())
766 std::string property = itr->asString();
767 if (checkingProperties.find(property) != checkingProperties.end())
769 checkingProperties.erase(property);
770 foundProperties.insert(property);
774 return !foundProperties.empty();