[cstdstring] demise Format, replacing with StringUtils::Format
[vuplus_xbmc] / xbmc / interfaces / json-rpc / AudioLibrary.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "AudioLibrary.h"
22 #include "music/MusicDatabase.h"
23 #include "FileItem.h"
24 #include "Util.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"
36
37 using namespace MUSIC_INFO;
38 using namespace JSONRPC;
39 using namespace XFILE;
40
41 JSONRPC_STATUS CAudioLibrary::GetArtists(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
42 {
43   CMusicDatabase musicdatabase;
44   if (!musicdatabase.Open())
45     return InternalError;
46
47   CMusicDbUrl musicUrl;
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())
62   {
63     CStdString xsp;
64     if (!GetXspFiltering("artists", filter, xsp))
65       return InvalidParams;
66
67     musicUrl.AddOption("xsp", xsp);
68   }
69
70   bool albumArtistsOnly = !CSettings::Get().GetBool("musiclibrary.showcompilationartists");
71   if (parameterObject["albumartistsonly"].isBoolean())
72     albumArtistsOnly = parameterObject["albumartistsonly"].asBoolean();
73
74   SortDescription sorting;
75   ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
76   if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
77     return InvalidParams;
78
79   CFileItemList items;
80   if (!musicdatabase.GetArtistsNav(musicUrl.ToString(), items, albumArtistsOnly, genreID, albumID, songID, CDatabase::Filter(), sorting))
81     return InternalError;
82
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");
88
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);
93   return OK;
94 }
95
96 JSONRPC_STATUS CAudioLibrary::GetArtistDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
97 {
98   int artistID = (int)parameterObject["artistid"].asInteger();
99
100   CMusicDbUrl musicUrl;
101   if (!musicUrl.FromString("musicdb://artists/"))
102     return InternalError;
103
104   CMusicDatabase musicdatabase;
105   if (!musicdatabase.Open())
106     return InternalError;
107
108   musicUrl.AddOption("artistid", artistID);
109
110   CFileItemList items;
111   CDatabase::Filter filter;
112   if (!musicdatabase.GetArtistsByWhere(musicUrl.ToString(), filter, items) || items.Size() != 1)
113     return InvalidParams;
114
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");
120
121   HandleFileItem("artistid", false, "artistdetails", items[0], param, param["properties"], result, false);
122   return OK;
123 }
124
125 JSONRPC_STATUS CAudioLibrary::GetAlbums(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
126 {
127   CMusicDatabase musicdatabase;
128   if (!musicdatabase.Open())
129     return InternalError;
130
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())
144   {
145     CStdString xsp;
146     if (!GetXspFiltering("albums", filter, xsp))
147       return InvalidParams;
148
149     musicUrl.AddOption("xsp", xsp);
150   }
151
152   SortDescription sorting;
153   ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
154   if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
155     return InvalidParams;
156
157   CFileItemList items;
158   if (!musicdatabase.GetAlbumsNav(musicUrl.ToString(), items, genreID, artistID, CDatabase::Filter(), sorting))
159     return InternalError;
160
161   JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
162   if (ret != OK)
163     return ret;
164
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);
169
170   return OK;
171 }
172
173 JSONRPC_STATUS CAudioLibrary::GetAlbumDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
174 {
175   int albumID = (int)parameterObject["albumid"].asInteger();
176
177   CMusicDatabase musicdatabase;
178   if (!musicdatabase.Open())
179     return InternalError;
180
181   CAlbum album;
182   if (!musicdatabase.GetAlbumInfo(albumID, album, NULL))
183     return InvalidParams;
184
185   CStdString path;
186   if (!musicdatabase.GetAlbumPath(albumID, path))
187     return InternalError;
188
189   CFileItemPtr albumItem;
190   FillAlbumItem(album, path, albumItem);
191
192   CFileItemList items;
193   items.Add(albumItem);
194   JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
195   if (ret != OK)
196     return ret;
197   
198   HandleFileItem("albumid", false, "albumdetails", items[0], parameterObject, parameterObject["properties"], result, false);
199
200   return OK;
201 }
202
203 JSONRPC_STATUS CAudioLibrary::GetSongs(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
204 {
205   CMusicDatabase musicdatabase;
206   if (!musicdatabase.Open())
207     return InternalError;
208
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())
226   {
227     CStdString xsp;
228     if (!GetXspFiltering("songs", filter, xsp))
229       return InvalidParams;
230
231     musicUrl.AddOption("xsp", xsp);
232   }
233
234   SortDescription sorting;
235   ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
236   if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
237     return InvalidParams;
238
239   CFileItemList items;
240   if (!musicdatabase.GetSongsNav(musicUrl.ToString(), items, genreID, artistID, albumID, sorting))
241     return InternalError;
242
243   JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
244   if (ret != OK)
245     return ret;
246
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);
251
252   return OK;
253 }
254
255 JSONRPC_STATUS CAudioLibrary::GetSongDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
256 {
257   int idSong = (int)parameterObject["songid"].asInteger();
258
259   CMusicDatabase musicdatabase;
260   if (!musicdatabase.Open())
261     return InternalError;
262
263   CSong song;
264   if (!musicdatabase.GetSong(idSong, song))
265     return InvalidParams;
266
267   CFileItemList items;
268   items.Add(CFileItemPtr(new CFileItem(song)));
269   JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
270   if (ret != OK)
271     return ret;
272
273   HandleFileItem("songid", true, "songdetails", items[0], parameterObject, parameterObject["properties"], result, false);
274   return OK;
275 }
276
277 JSONRPC_STATUS CAudioLibrary::GetRecentlyAddedAlbums(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
278 {
279   CMusicDatabase musicdatabase;
280   if (!musicdatabase.Open())
281     return InternalError;
282
283   VECALBUMS albums;
284   if (!musicdatabase.GetRecentlyAddedAlbums(albums))
285     return InternalError;
286
287   CFileItemList items;
288   for (unsigned int index = 0; index < albums.size(); index++)
289   {
290     CStdString path = StringUtils::Format("musicdb://recentlyaddedalbums/%i/", albums[index].idAlbum);
291
292     CFileItemPtr item;
293     FillAlbumItem(albums[index], path, item);
294     items.Add(item);
295   }
296
297   JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
298   if (ret != OK)
299     return ret;
300
301   HandleFileItemList("albumid", false, "albums", items, parameterObject, result);
302   return OK;
303 }
304
305 JSONRPC_STATUS CAudioLibrary::GetRecentlyAddedSongs(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
306 {
307   CMusicDatabase musicdatabase;
308   if (!musicdatabase.Open())
309     return InternalError;
310
311   int amount = (int)parameterObject["albumlimit"].asInteger();
312   if (amount < 0)
313     amount = 0;
314
315   CFileItemList items;
316   if (!musicdatabase.GetRecentlyAddedAlbumSongs("musicdb://", items, (unsigned int)amount))
317     return InternalError;
318
319   JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
320   if (ret != OK)
321     return ret;
322
323   HandleFileItemList("songid", true, "songs", items, parameterObject, result);
324   return OK;
325 }
326
327 JSONRPC_STATUS CAudioLibrary::GetRecentlyPlayedAlbums(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
328 {
329   CMusicDatabase musicdatabase;
330   if (!musicdatabase.Open())
331     return InternalError;
332
333   VECALBUMS albums;
334   if (!musicdatabase.GetRecentlyPlayedAlbums(albums))
335     return InternalError;
336
337   CFileItemList items;
338   for (unsigned int index = 0; index < albums.size(); index++)
339   {
340     CStdString path = StringUtils::Format("musicdb://recentlyplayedalbums/%i/", albums[index].idAlbum);
341
342     CFileItemPtr item;
343     FillAlbumItem(albums[index], path, item);
344     items.Add(item);
345   }
346
347   JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
348   if (ret != OK)
349     return ret;
350
351   HandleFileItemList("albumid", false, "albums", items, parameterObject, result);
352   return OK;
353 }
354
355 JSONRPC_STATUS CAudioLibrary::GetRecentlyPlayedSongs(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
356 {
357   CMusicDatabase musicdatabase;
358   if (!musicdatabase.Open())
359     return InternalError;
360
361   CFileItemList items;
362   if (!musicdatabase.GetRecentlyPlayedAlbumSongs("musicdb://", items))
363     return InternalError;
364
365   JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
366   if (ret != OK)
367     return ret;
368
369   HandleFileItemList("songid", true, "songs", items, parameterObject, result);
370   return OK;
371 }
372
373 JSONRPC_STATUS CAudioLibrary::GetGenres(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
374 {
375   CMusicDatabase musicdatabase;
376   if (!musicdatabase.Open())
377     return InternalError;
378
379   CFileItemList items;
380   if (!musicdatabase.GetGenresNav("musicdb://genres/", items))
381     return InternalError;
382
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());
386
387   HandleFileItemList("genreid", false, "genres", items, parameterObject, result);
388   return OK;
389 }
390
391 JSONRPC_STATUS CAudioLibrary::SetArtistDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
392 {
393   int id = (int)parameterObject["artistid"].asInteger();
394
395   CMusicDatabase musicdatabase;
396   if (!musicdatabase.Open())
397     return InternalError;
398
399   CArtist artist;
400   if (!musicdatabase.GetArtistInfo(id, artist) || artist.idArtist <= 0)
401     return InvalidParams;
402
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);
425
426   if (musicdatabase.SetArtistInfo(id, artist) <= 0)
427     return InternalError;
428
429   CJSONRPCUtils::NotifyItemUpdated();
430   return ACK;
431 }
432
433 JSONRPC_STATUS CAudioLibrary::SetAlbumDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
434 {
435   int id = (int)parameterObject["albumid"].asInteger();
436
437   CMusicDatabase musicdatabase;
438   if (!musicdatabase.Open())
439     return InternalError;
440
441   CAlbum album;
442   VECSONGS songs;
443   if (!musicdatabase.GetAlbumInfo(id, album, &songs) || album.idAlbum <= 0)
444     return InvalidParams;
445
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();
468
469   if (musicdatabase.SetAlbumInfo(id, album, songs) <= 0)
470     return InternalError;
471
472   CJSONRPCUtils::NotifyItemUpdated();
473   return ACK;
474 }
475
476 JSONRPC_STATUS CAudioLibrary::SetSongDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
477 {
478   int id = (int)parameterObject["songid"].asInteger();
479
480   CMusicDatabase musicdatabase;
481   if (!musicdatabase.Open())
482     return InternalError;
483
484   CSong song;
485   if (!musicdatabase.GetSong(id, song) || song.idSong != id)
486     return InvalidParams;
487
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();
512
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;
515
516   CJSONRPCUtils::NotifyItemUpdated();
517   return ACK;
518 }
519
520 JSONRPC_STATUS CAudioLibrary::Scan(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
521 {
522   std::string directory = parameterObject["directory"].asString();
523   CStdString cmd;
524   if (directory.empty())
525     cmd = "updatelibrary(music)";
526   else
527     cmd = StringUtils::Format("updatelibrary(music, %s)", StringUtils::Paramify(directory).c_str());
528
529   CApplicationMessenger::Get().ExecBuiltIn(cmd);
530   return ACK;
531 }
532
533 JSONRPC_STATUS CAudioLibrary::Export(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
534 {
535   CStdString cmd;
536   if (parameterObject["options"].isMember("path"))
537     cmd = StringUtils::Format("exportlibrary(music, false, %s)", StringUtils::Paramify(parameterObject["options"]["path"].asString()).c_str());
538   else
539     cmd = StringUtils::Format("exportlibrary(music, true, %s, %s)",
540                               parameterObject["options"]["images"].asBoolean() ? "true" : "false",
541                               parameterObject["options"]["overwrite"].asBoolean() ? "true" : "false");
542
543   CApplicationMessenger::Get().ExecBuiltIn(cmd);
544   return ACK;
545 }
546
547 JSONRPC_STATUS CAudioLibrary::Clean(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
548 {
549   CApplicationMessenger::Get().ExecBuiltIn("cleanlibrary(music)");
550   return ACK;
551 }
552
553 bool CAudioLibrary::FillFileItem(const CStdString &strFilename, CFileItemPtr &item, const CVariant &parameterObject /* = CVariant(CVariant::VariantTypeArray) */)
554 {
555   CMusicDatabase musicdatabase;
556   if (strFilename.empty())
557     return false;
558
559   bool filled = false;
560   if (musicdatabase.Open())
561   {
562     if (CDirectory::Exists(strFilename))
563     {
564       CAlbum album;
565       int albumid = musicdatabase.GetAlbumIdByPath(strFilename);
566       if (musicdatabase.GetAlbumInfo(albumid, album, NULL))
567       {
568         item->SetFromAlbum(album);
569
570         CFileItemList items;
571         items.Add(item);
572         if (GetAdditionalAlbumDetails(parameterObject, items, musicdatabase) == OK)
573           filled = true;
574       }
575     }
576     else
577     {
578       CSong song;
579       if (musicdatabase.GetSongByFileName(strFilename, song))
580       {
581         item->SetFromSong(song);
582
583         CFileItemList items;
584         items.Add(item);
585         if (GetAdditionalSongDetails(parameterObject, items, musicdatabase) == OK)
586           filled = true;
587       }
588     }
589   }
590
591   if (item->GetLabel().empty())
592   {
593     item->SetLabel(CUtil::GetTitleFromPath(strFilename, false));
594     if (item->GetLabel().empty())
595       item->SetLabel(URIUtils::GetFileName(strFilename));
596   }
597
598   return filled;
599 }
600
601 bool CAudioLibrary::FillFileItemList(const CVariant &parameterObject, CFileItemList &list)
602 {
603   CMusicDatabase musicdatabase;
604   if (!musicdatabase.Open())
605     return false;
606
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);
611
612   bool success = false;
613   CFileItemPtr fileItem(new CFileItem());
614   if (FillFileItem(file, fileItem, parameterObject))
615   {
616     success = true;
617     list.Add(fileItem);
618   }
619
620   if (artistID != -1 || albumID != -1 || genreID != -1)
621     success |= musicdatabase.GetSongsNav("musicdb://songs/", list, genreID, artistID, albumID);
622
623   int songID = (int)parameterObject["songid"].asInteger(-1);
624   if (songID != -1)
625   {
626     CSong song;
627     if (musicdatabase.GetSong(songID, song))
628     {
629       list.Add(CFileItemPtr(new CFileItem(song)));
630       success = true;
631     }
632   }
633
634   if (success)
635   {
636     // If we retrieved the list of songs by "artistid"
637     // we sort by album (and implicitly by track number)
638     if (artistID != -1)
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
645     else
646       list.Sort(SortByTrackNumber, SortOrderAscending);
647
648   }
649
650   return success;
651 }
652
653 void CAudioLibrary::FillAlbumItem(const CAlbum &album, const CStdString &path, CFileItemPtr &item)
654 {
655   item = CFileItemPtr(new CFileItem(path, album));
656 }
657
658 JSONRPC_STATUS CAudioLibrary::GetAdditionalAlbumDetails(const CVariant &parameterObject, CFileItemList &items, CMusicDatabase &musicdatabase)
659 {
660   if (!musicdatabase.Open())
661     return InternalError;
662
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))
668     return OK;
669
670   for (int i = 0; i < items.Size(); i++)
671   {
672     CFileItemPtr item = items[i];
673     if (additionalProperties.find("genreid") != additionalProperties.end())
674     {
675       std::vector<int> genreids;
676       if (musicdatabase.GetGenresByAlbum(item->GetMusicInfoTag()->GetDatabaseId(), genreids))
677       {
678         CVariant genreidObj(CVariant::VariantTypeArray);
679         for (std::vector<int>::const_iterator genreid = genreids.begin(); genreid != genreids.end(); ++genreid)
680           genreidObj.push_back(*genreid);
681
682         item->SetProperty("genreid", genreidObj);
683       }
684     }
685     if (additionalProperties.find("artistid") != additionalProperties.end())
686     {
687       std::vector<int> artistids;
688       if (musicdatabase.GetArtistsByAlbum(item->GetMusicInfoTag()->GetDatabaseId(), true, artistids))
689       {
690         CVariant artistidObj(CVariant::VariantTypeArray);
691         for (std::vector<int>::const_iterator artistid = artistids.begin(); artistid != artistids.end(); ++artistid)
692           artistidObj.push_back(*artistid);
693
694         item->SetProperty("artistid", artistidObj);
695       }
696     }
697   }
698
699   return OK;
700 }
701
702 JSONRPC_STATUS CAudioLibrary::GetAdditionalSongDetails(const CVariant &parameterObject, CFileItemList &items, CMusicDatabase &musicdatabase)
703 {
704   if (!musicdatabase.Open())
705     return InternalError;
706
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))
713     return OK;
714
715   for (int i = 0; i < items.Size(); i++)
716   {
717     CFileItemPtr item = items[i];
718     if (additionalProperties.find("genreid") != additionalProperties.end())
719     {
720       std::vector<int> genreids;
721       if (musicdatabase.GetGenresBySong(item->GetMusicInfoTag()->GetDatabaseId(), genreids))
722       {
723         CVariant genreidObj(CVariant::VariantTypeArray);
724         for (std::vector<int>::const_iterator genreid = genreids.begin(); genreid != genreids.end(); ++genreid)
725           genreidObj.push_back(*genreid);
726
727         item->SetProperty("genreid", genreidObj);
728       }
729     }
730     if (additionalProperties.find("artistid") != additionalProperties.end())
731     {
732       std::vector<int> artistids;
733       if (musicdatabase.GetArtistsBySong(item->GetMusicInfoTag()->GetDatabaseId(), true, artistids))
734       {
735         CVariant artistidObj(CVariant::VariantTypeArray);
736         for (std::vector<int>::const_iterator artistid = artistids.begin(); artistid != artistids.end(); ++artistid)
737           artistidObj.push_back(*artistid);
738
739         item->SetProperty("artistid", artistidObj);
740       }
741     }
742     if (additionalProperties.find("albumartistid") != additionalProperties.end() && item->GetMusicInfoTag()->GetAlbumId() > 0)
743     {
744       std::vector<int> albumartistids;
745       if (musicdatabase.GetArtistsByAlbum(item->GetMusicInfoTag()->GetAlbumId(), true, albumartistids))
746       {
747         CVariant albumartistidObj(CVariant::VariantTypeArray);
748         for (std::vector<int>::const_iterator albumartistid = albumartistids.begin(); albumartistid != albumartistids.end(); ++albumartistid)
749           albumartistidObj.push_back(*albumartistid);
750
751         item->SetProperty("albumartistid", albumartistidObj);
752       }
753     }
754   }
755
756   return OK;
757 }
758
759 bool CAudioLibrary::CheckForAdditionalProperties(const CVariant &properties, const std::set<std::string> &checkProperties, std::set<std::string> &foundProperties)
760 {
761   if (!properties.isArray() || properties.empty())
762     return false;
763
764   std::set<std::string> checkingProperties = checkProperties;
765   for (CVariant::const_iterator_array itr = properties.begin_array(); itr != properties.end_array() && !checkingProperties.empty(); itr++)
766   {
767     if (!itr->isString())
768       continue;
769
770     std::string property = itr->asString();
771     if (checkingProperties.find(property) != checkingProperties.end())
772     {
773       checkingProperties.erase(property);
774       foundProperties.insert(property);
775     }
776   }
777
778   return !foundProperties.empty();
779 }