5f92236614ea7379dd5acb2e739dcaf99e8a2ac8
[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;
291     path.Format("musicdb://recentlyaddedalbums/%i/", albums[index].idAlbum);
292
293     CFileItemPtr item;
294     FillAlbumItem(albums[index], path, item);
295     items.Add(item);
296   }
297
298   JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
299   if (ret != OK)
300     return ret;
301
302   HandleFileItemList("albumid", false, "albums", items, parameterObject, result);
303   return OK;
304 }
305
306 JSONRPC_STATUS CAudioLibrary::GetRecentlyAddedSongs(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
307 {
308   CMusicDatabase musicdatabase;
309   if (!musicdatabase.Open())
310     return InternalError;
311
312   int amount = (int)parameterObject["albumlimit"].asInteger();
313   if (amount < 0)
314     amount = 0;
315
316   CFileItemList items;
317   if (!musicdatabase.GetRecentlyAddedAlbumSongs("musicdb://", items, (unsigned int)amount))
318     return InternalError;
319
320   JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
321   if (ret != OK)
322     return ret;
323
324   HandleFileItemList("songid", true, "songs", items, parameterObject, result);
325   return OK;
326 }
327
328 JSONRPC_STATUS CAudioLibrary::GetRecentlyPlayedAlbums(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
329 {
330   CMusicDatabase musicdatabase;
331   if (!musicdatabase.Open())
332     return InternalError;
333
334   VECALBUMS albums;
335   if (!musicdatabase.GetRecentlyPlayedAlbums(albums))
336     return InternalError;
337
338   CFileItemList items;
339   for (unsigned int index = 0; index < albums.size(); index++)
340   {
341     CStdString path;
342     path.Format("musicdb://recentlyplayedalbums/%i/", albums[index].idAlbum);
343
344     CFileItemPtr item;
345     FillAlbumItem(albums[index], path, item);
346     items.Add(item);
347   }
348
349   JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
350   if (ret != OK)
351     return ret;
352
353   HandleFileItemList("albumid", false, "albums", items, parameterObject, result);
354   return OK;
355 }
356
357 JSONRPC_STATUS CAudioLibrary::GetRecentlyPlayedSongs(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
358 {
359   CMusicDatabase musicdatabase;
360   if (!musicdatabase.Open())
361     return InternalError;
362
363   CFileItemList items;
364   if (!musicdatabase.GetRecentlyPlayedAlbumSongs("musicdb://", items))
365     return InternalError;
366
367   JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
368   if (ret != OK)
369     return ret;
370
371   HandleFileItemList("songid", true, "songs", items, parameterObject, result);
372   return OK;
373 }
374
375 JSONRPC_STATUS CAudioLibrary::GetGenres(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
376 {
377   CMusicDatabase musicdatabase;
378   if (!musicdatabase.Open())
379     return InternalError;
380
381   CFileItemList items;
382   if (!musicdatabase.GetGenresNav("musicdb://genres/", items))
383     return InternalError;
384
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());
388
389   HandleFileItemList("genreid", false, "genres", items, parameterObject, result);
390   return OK;
391 }
392
393 JSONRPC_STATUS CAudioLibrary::SetArtistDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
394 {
395   int id = (int)parameterObject["artistid"].asInteger();
396
397   CMusicDatabase musicdatabase;
398   if (!musicdatabase.Open())
399     return InternalError;
400
401   CArtist artist;
402   if (!musicdatabase.GetArtistInfo(id, artist) || artist.idArtist <= 0)
403     return InvalidParams;
404
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);
427
428   if (musicdatabase.SetArtistInfo(id, artist) <= 0)
429     return InternalError;
430
431   CJSONRPCUtils::NotifyItemUpdated();
432   return ACK;
433 }
434
435 JSONRPC_STATUS CAudioLibrary::SetAlbumDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
436 {
437   int id = (int)parameterObject["albumid"].asInteger();
438
439   CMusicDatabase musicdatabase;
440   if (!musicdatabase.Open())
441     return InternalError;
442
443   CAlbum album;
444   VECSONGS songs;
445   if (!musicdatabase.GetAlbumInfo(id, album, &songs) || album.idAlbum <= 0)
446     return InvalidParams;
447
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();
470
471   if (musicdatabase.SetAlbumInfo(id, album, songs) <= 0)
472     return InternalError;
473
474   CJSONRPCUtils::NotifyItemUpdated();
475   return ACK;
476 }
477
478 JSONRPC_STATUS CAudioLibrary::SetSongDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
479 {
480   int id = (int)parameterObject["songid"].asInteger();
481
482   CMusicDatabase musicdatabase;
483   if (!musicdatabase.Open())
484     return InternalError;
485
486   CSong song;
487   if (!musicdatabase.GetSong(id, song) || song.idSong != id)
488     return InvalidParams;
489
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();
514
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;
517
518   CJSONRPCUtils::NotifyItemUpdated();
519   return ACK;
520 }
521
522 JSONRPC_STATUS CAudioLibrary::Scan(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
523 {
524   std::string directory = parameterObject["directory"].asString();
525   CStdString cmd;
526   if (directory.empty())
527     cmd = "updatelibrary(music)";
528   else
529     cmd.Format("updatelibrary(music, %s)", StringUtils::Paramify(directory).c_str());
530
531   CApplicationMessenger::Get().ExecBuiltIn(cmd);
532   return ACK;
533 }
534
535 JSONRPC_STATUS CAudioLibrary::Export(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
536 {
537   CStdString cmd;
538   if (parameterObject["options"].isMember("path"))
539     cmd.Format("exportlibrary(music, false, %s)", StringUtils::Paramify(parameterObject["options"]["path"].asString()));
540   else
541     cmd.Format("exportlibrary(music, true, %s, %s)",
542       parameterObject["options"]["images"].asBoolean() ? "true" : "false",
543       parameterObject["options"]["overwrite"].asBoolean() ? "true" : "false");
544
545   CApplicationMessenger::Get().ExecBuiltIn(cmd);
546   return ACK;
547 }
548
549 JSONRPC_STATUS CAudioLibrary::Clean(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
550 {
551   CApplicationMessenger::Get().ExecBuiltIn("cleanlibrary(music)");
552   return ACK;
553 }
554
555 bool CAudioLibrary::FillFileItem(const CStdString &strFilename, CFileItemPtr &item, const CVariant &parameterObject /* = CVariant(CVariant::VariantTypeArray) */)
556 {
557   CMusicDatabase musicdatabase;
558   if (strFilename.empty())
559     return false;
560
561   bool filled = false;
562   if (musicdatabase.Open())
563   {
564     if (CDirectory::Exists(strFilename))
565     {
566       CAlbum album;
567       int albumid = musicdatabase.GetAlbumIdByPath(strFilename);
568       if (musicdatabase.GetAlbumInfo(albumid, album, NULL))
569       {
570         item->SetFromAlbum(album);
571
572         CFileItemList items;
573         items.Add(item);
574         if (GetAdditionalAlbumDetails(parameterObject, items, musicdatabase) == OK)
575           filled = true;
576       }
577     }
578     else
579     {
580       CSong song;
581       if (musicdatabase.GetSongByFileName(strFilename, song))
582       {
583         item->SetFromSong(song);
584
585         CFileItemList items;
586         items.Add(item);
587         if (GetAdditionalSongDetails(parameterObject, items, musicdatabase) == OK)
588           filled = true;
589       }
590     }
591   }
592
593   if (item->GetLabel().empty())
594   {
595     item->SetLabel(CUtil::GetTitleFromPath(strFilename, false));
596     if (item->GetLabel().empty())
597       item->SetLabel(URIUtils::GetFileName(strFilename));
598   }
599
600   return filled;
601 }
602
603 bool CAudioLibrary::FillFileItemList(const CVariant &parameterObject, CFileItemList &list)
604 {
605   CMusicDatabase musicdatabase;
606   if (!musicdatabase.Open())
607     return false;
608
609   CStdString file = parameterObject["file"].asString();
610   int artistID = (int)parameterObject["artistid"].asInteger(-1);
611   int albumID = (int)parameterObject["albumid"].asInteger(-1);
612   int genreID = (int)parameterObject["genreid"].asInteger(-1);
613
614   bool success = false;
615   CFileItemPtr fileItem(new CFileItem());
616   if (FillFileItem(file, fileItem, parameterObject))
617   {
618     success = true;
619     list.Add(fileItem);
620   }
621
622   if (artistID != -1 || albumID != -1 || genreID != -1)
623     success |= musicdatabase.GetSongsNav("musicdb://songs/", list, genreID, artistID, albumID);
624
625   int songID = (int)parameterObject["songid"].asInteger(-1);
626   if (songID != -1)
627   {
628     CSong song;
629     if (musicdatabase.GetSong(songID, song))
630     {
631       list.Add(CFileItemPtr(new CFileItem(song)));
632       success = true;
633     }
634   }
635
636   if (success)
637   {
638     // If we retrieved the list of songs by "artistid"
639     // we sort by album (and implicitly by track number)
640     if (artistID != -1)
641       list.Sort(SortByAlbum, SortOrderAscending, SortAttributeIgnoreArticle);
642     // If we retrieve the list of songs by "genreid"
643     // we sort by artist (and implicitly by album and track number)
644     else if (genreID != -1)
645       list.Sort(SortByArtist, SortOrderAscending, SortAttributeIgnoreArticle);
646     // otherwise we sort by track number
647     else
648       list.Sort(SortByTrackNumber, SortOrderAscending);
649
650   }
651
652   return success;
653 }
654
655 void CAudioLibrary::FillAlbumItem(const CAlbum &album, const CStdString &path, CFileItemPtr &item)
656 {
657   item = CFileItemPtr(new CFileItem(path, album));
658 }
659
660 JSONRPC_STATUS CAudioLibrary::GetAdditionalAlbumDetails(const CVariant &parameterObject, CFileItemList &items, CMusicDatabase &musicdatabase)
661 {
662   if (!musicdatabase.Open())
663     return InternalError;
664
665   std::set<std::string> checkProperties;
666   checkProperties.insert("genreid");
667   checkProperties.insert("artistid");
668   std::set<std::string> additionalProperties;
669   if (!CheckForAdditionalProperties(parameterObject["properties"], checkProperties, additionalProperties))
670     return OK;
671
672   for (int i = 0; i < items.Size(); i++)
673   {
674     CFileItemPtr item = items[i];
675     if (additionalProperties.find("genreid") != additionalProperties.end())
676     {
677       std::vector<int> genreids;
678       if (musicdatabase.GetGenresByAlbum(item->GetMusicInfoTag()->GetDatabaseId(), genreids))
679       {
680         CVariant genreidObj(CVariant::VariantTypeArray);
681         for (std::vector<int>::const_iterator genreid = genreids.begin(); genreid != genreids.end(); ++genreid)
682           genreidObj.push_back(*genreid);
683
684         item->SetProperty("genreid", genreidObj);
685       }
686     }
687     if (additionalProperties.find("artistid") != additionalProperties.end())
688     {
689       std::vector<int> artistids;
690       if (musicdatabase.GetArtistsByAlbum(item->GetMusicInfoTag()->GetDatabaseId(), true, artistids))
691       {
692         CVariant artistidObj(CVariant::VariantTypeArray);
693         for (std::vector<int>::const_iterator artistid = artistids.begin(); artistid != artistids.end(); ++artistid)
694           artistidObj.push_back(*artistid);
695
696         item->SetProperty("artistid", artistidObj);
697       }
698     }
699   }
700
701   return OK;
702 }
703
704 JSONRPC_STATUS CAudioLibrary::GetAdditionalSongDetails(const CVariant &parameterObject, CFileItemList &items, CMusicDatabase &musicdatabase)
705 {
706   if (!musicdatabase.Open())
707     return InternalError;
708
709   std::set<std::string> checkProperties;
710   checkProperties.insert("genreid");
711   checkProperties.insert("artistid");
712   checkProperties.insert("albumartistid");
713   std::set<std::string> additionalProperties;
714   if (!CheckForAdditionalProperties(parameterObject["properties"], checkProperties, additionalProperties))
715     return OK;
716
717   for (int i = 0; i < items.Size(); i++)
718   {
719     CFileItemPtr item = items[i];
720     if (additionalProperties.find("genreid") != additionalProperties.end())
721     {
722       std::vector<int> genreids;
723       if (musicdatabase.GetGenresBySong(item->GetMusicInfoTag()->GetDatabaseId(), genreids))
724       {
725         CVariant genreidObj(CVariant::VariantTypeArray);
726         for (std::vector<int>::const_iterator genreid = genreids.begin(); genreid != genreids.end(); ++genreid)
727           genreidObj.push_back(*genreid);
728
729         item->SetProperty("genreid", genreidObj);
730       }
731     }
732     if (additionalProperties.find("artistid") != additionalProperties.end())
733     {
734       std::vector<int> artistids;
735       if (musicdatabase.GetArtistsBySong(item->GetMusicInfoTag()->GetDatabaseId(), true, artistids))
736       {
737         CVariant artistidObj(CVariant::VariantTypeArray);
738         for (std::vector<int>::const_iterator artistid = artistids.begin(); artistid != artistids.end(); ++artistid)
739           artistidObj.push_back(*artistid);
740
741         item->SetProperty("artistid", artistidObj);
742       }
743     }
744     if (additionalProperties.find("albumartistid") != additionalProperties.end() && item->GetMusicInfoTag()->GetAlbumId() > 0)
745     {
746       std::vector<int> albumartistids;
747       if (musicdatabase.GetArtistsByAlbum(item->GetMusicInfoTag()->GetAlbumId(), true, albumartistids))
748       {
749         CVariant albumartistidObj(CVariant::VariantTypeArray);
750         for (std::vector<int>::const_iterator albumartistid = albumartistids.begin(); albumartistid != albumartistids.end(); ++albumartistid)
751           albumartistidObj.push_back(*albumartistid);
752
753         item->SetProperty("albumartistid", albumartistidObj);
754       }
755     }
756   }
757
758   return OK;
759 }
760
761 bool CAudioLibrary::CheckForAdditionalProperties(const CVariant &properties, const std::set<std::string> &checkProperties, std::set<std::string> &foundProperties)
762 {
763   if (!properties.isArray() || properties.empty())
764     return false;
765
766   std::set<std::string> checkingProperties = checkProperties;
767   for (CVariant::const_iterator_array itr = properties.begin_array(); itr != properties.end_array() && !checkingProperties.empty(); itr++)
768   {
769     if (!itr->isString())
770       continue;
771
772     std::string property = itr->asString();
773     if (checkingProperties.find(property) != checkingProperties.end())
774     {
775       checkingProperties.erase(property);
776       foundProperties.insert(property);
777     }
778   }
779
780   return !foundProperties.empty();
781 }