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", true, "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++)
290 CStdString path = StringUtils::Format("musicdb://recentlyaddedalbums/%i/", albums[index].idAlbum);
293 FillAlbumItem(albums[index], path, item);
297 JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
301 HandleFileItemList("albumid", false, "albums", items, parameterObject, result);
305 JSONRPC_STATUS CAudioLibrary::GetRecentlyAddedSongs(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
307 CMusicDatabase musicdatabase;
308 if (!musicdatabase.Open())
309 return InternalError;
311 int amount = (int)parameterObject["albumlimit"].asInteger();
316 if (!musicdatabase.GetRecentlyAddedAlbumSongs("musicdb://", items, (unsigned int)amount))
317 return InternalError;
319 JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
323 HandleFileItemList("songid", true, "songs", items, parameterObject, result);
327 JSONRPC_STATUS CAudioLibrary::GetRecentlyPlayedAlbums(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
329 CMusicDatabase musicdatabase;
330 if (!musicdatabase.Open())
331 return InternalError;
334 if (!musicdatabase.GetRecentlyPlayedAlbums(albums))
335 return InternalError;
338 for (unsigned int index = 0; index < albums.size(); index++)
340 CStdString path = StringUtils::Format("musicdb://recentlyplayedalbums/%i/", albums[index].idAlbum);
343 FillAlbumItem(albums[index], path, item);
347 JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
351 HandleFileItemList("albumid", false, "albums", items, parameterObject, result);
355 JSONRPC_STATUS CAudioLibrary::GetRecentlyPlayedSongs(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
357 CMusicDatabase musicdatabase;
358 if (!musicdatabase.Open())
359 return InternalError;
362 if (!musicdatabase.GetRecentlyPlayedAlbumSongs("musicdb://", items))
363 return InternalError;
365 JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
369 HandleFileItemList("songid", true, "songs", items, parameterObject, result);
373 JSONRPC_STATUS CAudioLibrary::GetGenres(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
375 CMusicDatabase musicdatabase;
376 if (!musicdatabase.Open())
377 return InternalError;
380 if (!musicdatabase.GetGenresNav("musicdb://genres/", items))
381 return InternalError;
383 /* need to set strTitle in each item*/
384 for (unsigned int i = 0; i < (unsigned int)items.Size(); i++)
385 items[i]->GetMusicInfoTag()->SetTitle(items[i]->GetLabel());
387 HandleFileItemList("genreid", false, "genres", items, parameterObject, result);
391 JSONRPC_STATUS CAudioLibrary::SetArtistDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
393 int id = (int)parameterObject["artistid"].asInteger();
395 CMusicDatabase musicdatabase;
396 if (!musicdatabase.Open())
397 return InternalError;
400 if (!musicdatabase.GetArtistInfo(id, artist) || artist.idArtist <= 0)
401 return InvalidParams;
403 if (ParameterNotNull(parameterObject, "artist"))
404 artist.strArtist = parameterObject["artist"].asString();
405 if (ParameterNotNull(parameterObject, "instrument"))
406 CopyStringArray(parameterObject["instrument"], artist.instruments);
407 if (ParameterNotNull(parameterObject, "style"))
408 CopyStringArray(parameterObject["style"], artist.styles);
409 if (ParameterNotNull(parameterObject, "mood"))
410 CopyStringArray(parameterObject["mood"], artist.moods);
411 if (ParameterNotNull(parameterObject, "born"))
412 artist.strBorn = parameterObject["born"].asString();
413 if (ParameterNotNull(parameterObject, "formed"))
414 artist.strFormed = parameterObject["formed"].asString();
415 if (ParameterNotNull(parameterObject, "description"))
416 artist.strBiography = parameterObject["description"].asString();
417 if (ParameterNotNull(parameterObject, "genre"))
418 CopyStringArray(parameterObject["genre"], artist.genre);
419 if (ParameterNotNull(parameterObject, "died"))
420 artist.strDied = parameterObject["died"].asString();
421 if (ParameterNotNull(parameterObject, "disbanded"))
422 artist.strDisbanded = parameterObject["disbanded"].asString();
423 if (ParameterNotNull(parameterObject, "yearsactive"))
424 CopyStringArray(parameterObject["yearsactive"], artist.yearsActive);
426 if (musicdatabase.SetArtistInfo(id, artist) <= 0)
427 return InternalError;
429 CJSONRPCUtils::NotifyItemUpdated();
433 JSONRPC_STATUS CAudioLibrary::SetAlbumDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
435 int id = (int)parameterObject["albumid"].asInteger();
437 CMusicDatabase musicdatabase;
438 if (!musicdatabase.Open())
439 return InternalError;
443 if (!musicdatabase.GetAlbumInfo(id, album, &songs) || album.idAlbum <= 0)
444 return InvalidParams;
446 if (ParameterNotNull(parameterObject, "title"))
447 album.strAlbum = parameterObject["title"].asString();
448 if (ParameterNotNull(parameterObject, "artist"))
449 CopyStringArray(parameterObject["artist"], album.artist);
450 if (ParameterNotNull(parameterObject, "description"))
451 album.strReview = parameterObject["description"].asString();
452 if (ParameterNotNull(parameterObject, "genre"))
453 CopyStringArray(parameterObject["genre"], album.genre);
454 if (ParameterNotNull(parameterObject, "theme"))
455 CopyStringArray(parameterObject["theme"], album.themes);
456 if (ParameterNotNull(parameterObject, "mood"))
457 CopyStringArray(parameterObject["mood"], album.moods);
458 if (ParameterNotNull(parameterObject, "style"))
459 CopyStringArray(parameterObject["style"], album.styles);
460 if (ParameterNotNull(parameterObject, "type"))
461 album.strType = parameterObject["type"].asString();
462 if (ParameterNotNull(parameterObject, "albumlabel"))
463 album.strLabel = parameterObject["albumlabel"].asString();
464 if (ParameterNotNull(parameterObject, "rating"))
465 album.iRating = (int)parameterObject["rating"].asInteger();
466 if (ParameterNotNull(parameterObject, "year"))
467 album.iYear = (int)parameterObject["year"].asInteger();
469 if (musicdatabase.SetAlbumInfo(id, album, songs) <= 0)
470 return InternalError;
472 CJSONRPCUtils::NotifyItemUpdated();
476 JSONRPC_STATUS CAudioLibrary::SetSongDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
478 int id = (int)parameterObject["songid"].asInteger();
480 CMusicDatabase musicdatabase;
481 if (!musicdatabase.Open())
482 return InternalError;
485 if (!musicdatabase.GetSong(id, song) || song.idSong != id)
486 return InvalidParams;
488 if (ParameterNotNull(parameterObject, "title"))
489 song.strTitle = parameterObject["title"].asString();
490 if (ParameterNotNull(parameterObject, "artist"))
491 CopyStringArray(parameterObject["artist"], song.artist);
492 if (ParameterNotNull(parameterObject, "albumartist"))
493 CopyStringArray(parameterObject["albumartist"], song.albumArtist);
494 if (ParameterNotNull(parameterObject, "genre"))
495 CopyStringArray(parameterObject["genre"], song.genre);
496 if (ParameterNotNull(parameterObject, "year"))
497 song.iYear = (int)parameterObject["year"].asInteger();
498 if (ParameterNotNull(parameterObject, "rating"))
499 song.rating = '0' + (char)parameterObject["rating"].asInteger();
500 if (ParameterNotNull(parameterObject, "album"))
501 song.strAlbum = parameterObject["album"].asString();
502 if (ParameterNotNull(parameterObject, "track"))
503 song.iTrack = (song.iTrack & 0xffff0000) | ((int)parameterObject["track"].asInteger() & 0xffff);
504 if (ParameterNotNull(parameterObject, "disc"))
505 song.iTrack = (song.iTrack & 0xffff) | ((int)parameterObject["disc"].asInteger() << 16);
506 if (ParameterNotNull(parameterObject, "duration"))
507 song.iDuration = (int)parameterObject["duration"].asInteger();
508 if (ParameterNotNull(parameterObject, "comment"))
509 song.strComment = parameterObject["comment"].asString();
510 if (ParameterNotNull(parameterObject, "musicbrainztrackid"))
511 song.strMusicBrainzTrackID = parameterObject["musicbrainztrackid"].asString();
513 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)
514 return InternalError;
516 CJSONRPCUtils::NotifyItemUpdated();
520 JSONRPC_STATUS CAudioLibrary::Scan(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
522 std::string directory = parameterObject["directory"].asString();
524 if (directory.empty())
525 cmd = "updatelibrary(music)";
527 cmd = StringUtils::Format("updatelibrary(music, %s)", StringUtils::Paramify(directory).c_str());
529 CApplicationMessenger::Get().ExecBuiltIn(cmd);
533 JSONRPC_STATUS CAudioLibrary::Export(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
536 if (parameterObject["options"].isMember("path"))
537 cmd = StringUtils::Format("exportlibrary(music, false, %s)", StringUtils::Paramify(parameterObject["options"]["path"].asString()).c_str());
539 cmd = StringUtils::Format("exportlibrary(music, true, %s, %s)",
540 parameterObject["options"]["images"].asBoolean() ? "true" : "false",
541 parameterObject["options"]["overwrite"].asBoolean() ? "true" : "false");
543 CApplicationMessenger::Get().ExecBuiltIn(cmd);
547 JSONRPC_STATUS CAudioLibrary::Clean(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
549 CApplicationMessenger::Get().ExecBuiltIn("cleanlibrary(music)");
553 bool CAudioLibrary::FillFileItem(const CStdString &strFilename, CFileItemPtr &item, const CVariant ¶meterObject /* = CVariant(CVariant::VariantTypeArray) */)
555 CMusicDatabase musicdatabase;
556 if (strFilename.empty())
560 if (musicdatabase.Open())
562 if (CDirectory::Exists(strFilename))
565 int albumid = musicdatabase.GetAlbumIdByPath(strFilename);
566 if (musicdatabase.GetAlbumInfo(albumid, album, NULL))
568 item->SetFromAlbum(album);
572 if (GetAdditionalAlbumDetails(parameterObject, items, musicdatabase) == OK)
579 if (musicdatabase.GetSongByFileName(strFilename, song))
581 item->SetFromSong(song);
585 if (GetAdditionalSongDetails(parameterObject, items, musicdatabase) == OK)
591 if (item->GetLabel().empty())
593 item->SetLabel(CUtil::GetTitleFromPath(strFilename, false));
594 if (item->GetLabel().empty())
595 item->SetLabel(URIUtils::GetFileName(strFilename));
601 bool CAudioLibrary::FillFileItemList(const CVariant ¶meterObject, CFileItemList &list)
603 CMusicDatabase musicdatabase;
604 if (!musicdatabase.Open())
607 CStdString file = parameterObject["file"].asString();
608 int artistID = (int)parameterObject["artistid"].asInteger(-1);
609 int albumID = (int)parameterObject["albumid"].asInteger(-1);
610 int genreID = (int)parameterObject["genreid"].asInteger(-1);
612 bool success = false;
613 CFileItemPtr fileItem(new CFileItem());
614 if (FillFileItem(file, fileItem, parameterObject))
620 if (artistID != -1 || albumID != -1 || genreID != -1)
621 success |= musicdatabase.GetSongsNav("musicdb://songs/", list, genreID, artistID, albumID);
623 int songID = (int)parameterObject["songid"].asInteger(-1);
627 if (musicdatabase.GetSong(songID, song))
629 list.Add(CFileItemPtr(new CFileItem(song)));
636 // If we retrieved the list of songs by "artistid"
637 // we sort by album (and implicitly by track number)
639 list.Sort(SortByAlbum, SortOrderAscending, SortAttributeIgnoreArticle);
640 // If we retrieve the list of songs by "genreid"
641 // we sort by artist (and implicitly by album and track number)
642 else if (genreID != -1)
643 list.Sort(SortByArtist, SortOrderAscending, SortAttributeIgnoreArticle);
644 // otherwise we sort by track number
646 list.Sort(SortByTrackNumber, SortOrderAscending);
653 void CAudioLibrary::FillAlbumItem(const CAlbum &album, const CStdString &path, CFileItemPtr &item)
655 item = CFileItemPtr(new CFileItem(path, album));
658 JSONRPC_STATUS CAudioLibrary::GetAdditionalAlbumDetails(const CVariant ¶meterObject, CFileItemList &items, CMusicDatabase &musicdatabase)
660 if (!musicdatabase.Open())
661 return InternalError;
663 std::set<std::string> checkProperties;
664 checkProperties.insert("genreid");
665 checkProperties.insert("artistid");
666 std::set<std::string> additionalProperties;
667 if (!CheckForAdditionalProperties(parameterObject["properties"], checkProperties, additionalProperties))
670 for (int i = 0; i < items.Size(); i++)
672 CFileItemPtr item = items[i];
673 if (additionalProperties.find("genreid") != additionalProperties.end())
675 std::vector<int> genreids;
676 if (musicdatabase.GetGenresByAlbum(item->GetMusicInfoTag()->GetDatabaseId(), genreids))
678 CVariant genreidObj(CVariant::VariantTypeArray);
679 for (std::vector<int>::const_iterator genreid = genreids.begin(); genreid != genreids.end(); ++genreid)
680 genreidObj.push_back(*genreid);
682 item->SetProperty("genreid", genreidObj);
685 if (additionalProperties.find("artistid") != additionalProperties.end())
687 std::vector<int> artistids;
688 if (musicdatabase.GetArtistsByAlbum(item->GetMusicInfoTag()->GetDatabaseId(), true, artistids))
690 CVariant artistidObj(CVariant::VariantTypeArray);
691 for (std::vector<int>::const_iterator artistid = artistids.begin(); artistid != artistids.end(); ++artistid)
692 artistidObj.push_back(*artistid);
694 item->SetProperty("artistid", artistidObj);
702 JSONRPC_STATUS CAudioLibrary::GetAdditionalSongDetails(const CVariant ¶meterObject, CFileItemList &items, CMusicDatabase &musicdatabase)
704 if (!musicdatabase.Open())
705 return InternalError;
707 std::set<std::string> checkProperties;
708 checkProperties.insert("genreid");
709 checkProperties.insert("artistid");
710 checkProperties.insert("albumartistid");
711 std::set<std::string> additionalProperties;
712 if (!CheckForAdditionalProperties(parameterObject["properties"], checkProperties, additionalProperties))
715 for (int i = 0; i < items.Size(); i++)
717 CFileItemPtr item = items[i];
718 if (additionalProperties.find("genreid") != additionalProperties.end())
720 std::vector<int> genreids;
721 if (musicdatabase.GetGenresBySong(item->GetMusicInfoTag()->GetDatabaseId(), genreids))
723 CVariant genreidObj(CVariant::VariantTypeArray);
724 for (std::vector<int>::const_iterator genreid = genreids.begin(); genreid != genreids.end(); ++genreid)
725 genreidObj.push_back(*genreid);
727 item->SetProperty("genreid", genreidObj);
730 if (additionalProperties.find("artistid") != additionalProperties.end())
732 std::vector<int> artistids;
733 if (musicdatabase.GetArtistsBySong(item->GetMusicInfoTag()->GetDatabaseId(), true, artistids))
735 CVariant artistidObj(CVariant::VariantTypeArray);
736 for (std::vector<int>::const_iterator artistid = artistids.begin(); artistid != artistids.end(); ++artistid)
737 artistidObj.push_back(*artistid);
739 item->SetProperty("artistid", artistidObj);
742 if (additionalProperties.find("albumartistid") != additionalProperties.end() && item->GetMusicInfoTag()->GetAlbumId() > 0)
744 std::vector<int> albumartistids;
745 if (musicdatabase.GetArtistsByAlbum(item->GetMusicInfoTag()->GetAlbumId(), true, albumartistids))
747 CVariant albumartistidObj(CVariant::VariantTypeArray);
748 for (std::vector<int>::const_iterator albumartistid = albumartistids.begin(); albumartistid != albumartistids.end(); ++albumartistid)
749 albumartistidObj.push_back(*albumartistid);
751 item->SetProperty("albumartistid", albumartistidObj);
759 bool CAudioLibrary::CheckForAdditionalProperties(const CVariant &properties, const std::set<std::string> &checkProperties, std::set<std::string> &foundProperties)
761 if (!properties.isArray() || properties.empty())
764 std::set<std::string> checkingProperties = checkProperties;
765 for (CVariant::const_iterator_array itr = properties.begin_array(); itr != properties.end_array() && !checkingProperties.empty(); itr++)
767 if (!itr->isString())
770 std::string property = itr->asString();
771 if (checkingProperties.find(property) != checkingProperties.end())
773 checkingProperties.erase(property);
774 foundProperties.insert(property);
778 return !foundProperties.empty();