jsonrpc: add "genreid" property for albums and songs
authormontellese <montellese@xbmc.org>
Wed, 21 Nov 2012 09:29:11 +0000 (10:29 +0100)
committermontellese <montellese@xbmc.org>
Sun, 25 Nov 2012 20:01:59 +0000 (21:01 +0100)
xbmc/interfaces/json-rpc/AudioLibrary.cpp
xbmc/interfaces/json-rpc/AudioLibrary.h
xbmc/interfaces/json-rpc/FileItemHandler.cpp
xbmc/interfaces/json-rpc/FileOperations.cpp
xbmc/interfaces/json-rpc/FileOperations.h
xbmc/interfaces/json-rpc/PlayerOperations.cpp
xbmc/interfaces/json-rpc/ServiceDescription.h
xbmc/interfaces/json-rpc/types.json
xbmc/music/MusicDatabase.cpp
xbmc/music/MusicDatabase.h

index 6eaaefd..8769956 100644 (file)
@@ -157,6 +157,10 @@ JSONRPC_STATUS CAudioLibrary::GetAlbums(const CStdString &method, ITransportLaye
   if (!musicdatabase.GetAlbumsNav(musicUrl.ToString(), items, genreID, artistID, CDatabase::Filter(), sorting))
     return InternalError;
 
+  JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
+  if (ret != OK)
+    return ret;
+
   int size = items.Size();
   if (items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
     size = (int)items.GetProperty("total").asInteger();
@@ -181,9 +185,16 @@ JSONRPC_STATUS CAudioLibrary::GetAlbumDetails(const CStdString &method, ITranspo
   if (!musicdatabase.GetAlbumPath(albumID, path))
     return InternalError;
 
-  CFileItemPtr m_albumItem;
-  FillAlbumItem(album, path, m_albumItem);
-  HandleFileItem("albumid", false, "albumdetails", m_albumItem, parameterObject, parameterObject["properties"], result, false);
+  CFileItemPtr albumItem;
+  FillAlbumItem(album, path, albumItem);
+
+  CFileItemList items;
+  items.Add(albumItem);
+  JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
+  if (ret != OK)
+    return ret;
+  
+  HandleFileItem("albumid", false, "albumdetails", items[0], parameterObject, parameterObject["properties"], result, false);
 
   return OK;
 }
@@ -228,6 +239,10 @@ JSONRPC_STATUS CAudioLibrary::GetSongs(const CStdString &method, ITransportLayer
   if (!musicdatabase.GetSongsNav(musicUrl.ToString(), items, genreID, artistID, albumID, sorting))
     return InternalError;
 
+  JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
+  if (ret != OK)
+    return ret;
+
   int size = items.Size();
   if (items.HasProperty("total") && items.GetProperty("total").asInteger() > size)
     size = (int)items.GetProperty("total").asInteger();
@@ -248,7 +263,13 @@ JSONRPC_STATUS CAudioLibrary::GetSongDetails(const CStdString &method, ITranspor
   if (!musicdatabase.GetSongById(idSong, song))
     return InvalidParams;
 
-  HandleFileItem("songid", false, "songdetails", CFileItemPtr( new CFileItem(song) ), parameterObject, parameterObject["properties"], result, false);
+  CFileItemList items;
+  items.Add(CFileItemPtr(new CFileItem(song)));
+  JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
+  if (ret != OK)
+    return ret;
+
+  HandleFileItem("songid", false, "songdetails", items[0], parameterObject, parameterObject["properties"], result, false);
   return OK;
 }
 
@@ -273,6 +294,10 @@ JSONRPC_STATUS CAudioLibrary::GetRecentlyAddedAlbums(const CStdString &method, I
     items.Add(item);
   }
 
+  JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
+  if (ret != OK)
+    return ret;
+
   HandleFileItemList("albumid", false, "albums", items, parameterObject, result);
   return OK;
 }
@@ -291,6 +316,10 @@ JSONRPC_STATUS CAudioLibrary::GetRecentlyAddedSongs(const CStdString &method, IT
   if (!musicdatabase.GetRecentlyAddedAlbumSongs("musicdb://", items, (unsigned int)amount))
     return InternalError;
 
+  JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
+  if (ret != OK)
+    return ret;
+
   HandleFileItemList("songid", true, "songs", items, parameterObject, result);
   return OK;
 }
@@ -316,6 +345,10 @@ JSONRPC_STATUS CAudioLibrary::GetRecentlyPlayedAlbums(const CStdString &method,
     items.Add(item);
   }
 
+  JSONRPC_STATUS ret = GetAdditionalAlbumDetails(parameterObject, items, musicdatabase);
+  if (ret != OK)
+    return ret;
+
   HandleFileItemList("albumid", false, "albums", items, parameterObject, result);
   return OK;
 }
@@ -330,6 +363,10 @@ JSONRPC_STATUS CAudioLibrary::GetRecentlyPlayedSongs(const CStdString &method, I
   if (!musicdatabase.GetRecentlyPlayedAlbumSongs("musicdb://", items))
     return InternalError;
 
+  JSONRPC_STATUS ret = GetAdditionalSongDetails(parameterObject, items, musicdatabase);
+  if (ret != OK)
+    return ret;
+
   HandleFileItemList("songid", true, "songs", items, parameterObject, result);
   return OK;
 }
@@ -520,7 +557,7 @@ JSONRPC_STATUS CAudioLibrary::Clean(const CStdString &method, ITransportLayer *t
   return ACK;
 }
 
-bool CAudioLibrary::FillFileItem(const CStdString &strFilename, CFileItem &item)
+bool CAudioLibrary::FillFileItem(const CStdString &strFilename, CFileItem &item, const CVariant &parameterObject /* = CVariant(CVariant::VariantTypeArray) */)
 {
   CMusicDatabase musicdatabase;
   if (strFilename.empty() || !musicdatabase.Open())
@@ -534,6 +571,11 @@ bool CAudioLibrary::FillFileItem(const CStdString &strFilename, CFileItem &item)
       return false;
 
     item.SetFromAlbum(album);
+
+    CFileItemList items;
+    items.Add(CFileItemPtr(&item));
+    if (GetAdditionalAlbumDetails(parameterObject, items, musicdatabase) != OK)
+      return false;
   }
   else
   {
@@ -542,6 +584,11 @@ bool CAudioLibrary::FillFileItem(const CStdString &strFilename, CFileItem &item)
       return false;
 
     item.SetFromSong(song);
+
+    CFileItemList items;
+    items.Add(CFileItemPtr(&item));
+    if (GetAdditionalSongDetails(parameterObject, items, musicdatabase) != OK)
+      return false;
   }
 
   return true;
@@ -560,7 +607,7 @@ bool CAudioLibrary::FillFileItemList(const CVariant &parameterObject, CFileItemL
 
   bool success = false;
   CFileItem fileItem;
-  if (FillFileItem(file, fileItem))
+  if (FillFileItem(file, fileItem, parameterObject))
   {
     success = true;
     list.Add(CFileItemPtr(new CFileItem(fileItem)));
@@ -603,3 +650,87 @@ void CAudioLibrary::FillAlbumItem(const CAlbum &album, const CStdString &path, C
 {
   item = CFileItemPtr(new CFileItem(path, album));
 }
+
+JSONRPC_STATUS CAudioLibrary::GetAdditionalAlbumDetails(const CVariant &parameterObject, CFileItemList &items, CMusicDatabase &musicdatabase)
+{
+  if (!musicdatabase.Open())
+    return InternalError;
+
+  std::set<std::string> checkProperties;
+  checkProperties.insert("genreid");
+  std::set<std::string> additionalProperties;
+  if (!CheckForAdditionalProperties(parameterObject["properties"], checkProperties, additionalProperties))
+    return OK;
+
+  for (int i = 0; i < items.Size(); i++)
+  {
+    CFileItemPtr item = items[i];
+    if (additionalProperties.find("genreid") != additionalProperties.end())
+    {
+      std::vector<int> genreids;
+      if (musicdatabase.GetGenresByAlbum(item->GetMusicInfoTag()->GetDatabaseId(), genreids))
+      {
+        CVariant genreidObj(CVariant::VariantTypeArray);
+        for (std::vector<int>::const_iterator genreid = genreids.begin(); genreid != genreids.end(); genreid++)
+          genreidObj.push_back(*genreid);
+
+        item->SetProperty("genreid", genreidObj);
+      }
+    }
+  }
+
+  return OK;
+}
+
+JSONRPC_STATUS CAudioLibrary::GetAdditionalSongDetails(const CVariant &parameterObject, CFileItemList &items, CMusicDatabase &musicdatabase)
+{
+  if (!musicdatabase.Open())
+    return InternalError;
+
+  std::set<std::string> checkProperties;
+  checkProperties.insert("genreid");
+  std::set<std::string> additionalProperties;
+  if (!CheckForAdditionalProperties(parameterObject["properties"], checkProperties, additionalProperties))
+    return OK;
+
+  for (int i = 0; i < items.Size(); i++)
+  {
+    CFileItemPtr item = items[i];
+    if (additionalProperties.find("genreid") != additionalProperties.end())
+    {
+      std::vector<int> genreids;
+      if (musicdatabase.GetGenresBySong(item->GetMusicInfoTag()->GetDatabaseId(), genreids))
+      {
+        CVariant genreidObj(CVariant::VariantTypeArray);
+        for (std::vector<int>::const_iterator genreid = genreids.begin(); genreid != genreids.end(); genreid++)
+          genreidObj.push_back(*genreid);
+
+        item->SetProperty("genreid", genreidObj);
+      }
+    }
+  }
+
+  return OK;
+}
+
+bool CAudioLibrary::CheckForAdditionalProperties(const CVariant &properties, const std::set<std::string> &checkProperties, std::set<std::string> &foundProperties)
+{
+  if (!properties.isArray() || properties.empty())
+    return false;
+
+  std::set<std::string> checkingProperties = checkProperties;
+  for (CVariant::const_iterator_array itr = properties.begin_array(); itr != properties.end_array() && !checkingProperties.empty(); itr++)
+  {
+    if (!itr->isString())
+      continue;
+
+    std::string property = itr->asString();
+    if (checkingProperties.find(property) != checkingProperties.end())
+    {
+      checkingProperties.erase(property);
+      foundProperties.insert(property);
+    }
+  }
+
+  return !foundProperties.empty();
+}
index eb1d5eb..82a971f 100644 (file)
  *
  */
 
+#include <set>
+
 #include "utils/StdString.h"
 #include "JSONRPC.h"
 #include "FileItemHandler.h"
 
+class CMusicDatabase;
+
 namespace JSONRPC
 {
   class CAudioLibrary : public CFileItemHandler
@@ -49,10 +53,15 @@ namespace JSONRPC
     static JSONRPC_STATUS Export(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
     static JSONRPC_STATUS Clean(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
 
-    static bool FillFileItem(const CStdString &strFilename, CFileItem &item);
+    static bool FillFileItem(const CStdString &strFilename, CFileItem &item, const CVariant &parameterObject = CVariant(CVariant::VariantTypeArray));
     static bool FillFileItemList(const CVariant &parameterObject, CFileItemList &list);
 
+    static JSONRPC_STATUS GetAdditionalAlbumDetails(const CVariant &parameterObject, CFileItemList &items, CMusicDatabase &musicdatabase);
+    static JSONRPC_STATUS GetAdditionalSongDetails(const CVariant &parameterObject, CFileItemList &items, CMusicDatabase &musicdatabase);
+
   private:
     static void FillAlbumItem(const CAlbum &album, const CStdString &path, CFileItemPtr &item);
+    
+    static bool CheckForAdditionalProperties(const CVariant &properties, const std::set<std::string> &checkProperties, std::set<std::string> &foundProperties);
   };
 }
index bf7fcb3..3cd9294 100644 (file)
@@ -164,6 +164,12 @@ bool CFileItemHandler::GetField(const std::string &field, const CVariant &info,
       result[field] = item->m_dateTime.GetAsLocalizedDateTime();
       return true;
     }
+
+    if (item->HasProperty(field))
+    {
+      result[field] = item->GetProperty(field);
+      return true;
+    }
   }
 
   return false;
index 58c13a9..8d3ea6b 100644 (file)
@@ -139,7 +139,7 @@ JSONRPC_STATUS CFileOperations::GetDirectory(const CStdString &method, ITranspor
       else
       {
         CFileItem fileItem;
-        if (FillFileItem(items[i], fileItem, media))
+        if (FillFileItem(items[i], fileItem, media, parameterObject))
         {
           if (items[i]->m_bIsFolder)
             filteredDirectories.Add(CFileItemPtr(new CFileItem(fileItem)));
@@ -214,7 +214,7 @@ JSONRPC_STATUS CFileOperations::GetFileDetails(const CStdString &method, ITransp
 
   CFileItemPtr item = items.Get(file);
   if (!URIUtils::IsUPnP(file))
-    FillFileItem(item, *item.get(), parameterObject["media"].asString());
+    FillFileItem(item, *item.get(), parameterObject["media"].asString(), parameterObject);
 
   // Check if the "properties" list exists
   // and make sure it contains the "file"
@@ -263,7 +263,7 @@ JSONRPC_STATUS CFileOperations::Download(const CStdString &method, ITransportLay
   return transport->Download(parameterObject["path"].asString().c_str(), result) ? OK : InvalidParams;
 }
 
-bool CFileOperations::FillFileItem(const CFileItemPtr &originalItem, CFileItem &item, CStdString media /* = "" */)
+bool CFileOperations::FillFileItem(const CFileItemPtr &originalItem, CFileItem &item, CStdString media /* = "" */, const CVariant &parameterObject /* = CVariant(CVariant::VariantTypeArray) */)
 {
   if (originalItem.get() == NULL)
     return false;
@@ -278,7 +278,7 @@ bool CFileOperations::FillFileItem(const CFileItemPtr &originalItem, CFileItem &
     if (media.Equals("video"))
       status = CVideoLibrary::FillFileItem(strFilename, item);
     else if (media.Equals("music"))
-      status = CAudioLibrary::FillFileItem(strFilename, item);
+      status = CAudioLibrary::FillFileItem(strFilename, item, parameterObject);
 
     if (status && item.GetLabel().empty())
     {
@@ -364,7 +364,7 @@ bool CFileOperations::FillFileItemList(const CVariant &parameterObject, CFileIte
           else
           {
             CFileItem fileItem;
-            if (FillFileItem(items[i], fileItem, media))
+            if (FillFileItem(items[i], fileItem, media, parameterObject))
               list.Add(CFileItemPtr(new CFileItem(fileItem)));
             else if (media == "files")
               list.Add(items[i]);
index 6daa5cd..6e51354 100644 (file)
@@ -35,7 +35,7 @@ namespace JSONRPC
     static JSONRPC_STATUS PrepareDownload(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
     static JSONRPC_STATUS Download(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
 
-    static bool FillFileItem(const CFileItemPtr &originalItem, CFileItem &item, CStdString media = "");
+    static bool FillFileItem(const CFileItemPtr &originalItem, CFileItem &item, CStdString media = "", const CVariant &parameterObject = CVariant(CVariant::VariantTypeArray));
     static bool FillFileItemList(const CVariant &parameterObject, CFileItemList &list);
   };
 }
index e50a4db..ad22377 100644 (file)
@@ -37,6 +37,7 @@
 #include "filesystem/File.h"
 #include "PartyModeManager.h"
 #include "epg/EpgInfoTag.h"
+#include "music/MusicDatabase.h"
 #include "pvr/PVRManager.h"
 #include "pvr/channels/PVRChannel.h"
 #include "pvr/channels/PVRChannelGroupsContainer.h"
@@ -125,7 +126,7 @@ JSONRPC_STATUS CPlayerOperations::GetItem(const CStdString &method, ITransportLa
         }
         else
         {
-          if (!CAudioLibrary::FillFileItem(g_application.CurrentFile(), tmpItem))
+          if (!CAudioLibrary::FillFileItem(g_application.CurrentFile(), tmpItem, parameterObject))
           {
             tmpItem = CFileItem(*g_infoManager.GetCurrentSongTag());
             tmpItem.SetPath(g_application.CurrentFileItem().GetPath());
@@ -137,7 +138,10 @@ JSONRPC_STATUS CPlayerOperations::GetItem(const CStdString &method, ITransportLa
       else
         fileItem = CFileItemPtr(new CFileItem(g_application.CurrentFileItem()));
 
-      if (player == Video && !IsPVRChannel())
+      if (IsPVRChannel())
+        break;
+
+      if (player == Video)
       {
         bool additionalInfo = false;
         for (CVariant::const_iterator_array itr = parameterObject["properties"].begin_array(); itr != parameterObject["properties"].end_array(); itr++)
@@ -176,6 +180,16 @@ JSONRPC_STATUS CPlayerOperations::GetItem(const CStdString &method, ITransportLa
           }
         }
       }
+      else if (player == Audio)
+      {
+        if (fileItem->IsMusicDb())
+        {
+          CMusicDatabase musicdb;
+          CFileItemList items;
+          items.Add(fileItem);
+          CAudioLibrary::GetAdditionalSongDetails(parameterObject, items, musicdb);
+        }
+      }
       break;
     }
 
index e0149c8..e557af3 100644 (file)
@@ -423,7 +423,7 @@ namespace JSONRPC
                   "\"theme\", \"mood\", \"style\", \"type\", \"albumlabel\","
                   "\"rating\", \"year\", \"musicbrainzalbumid\","
                   "\"musicbrainzalbumartistid\", \"fanart\", \"thumbnail\","
-                  "\"playcount\" ]"
+                  "\"playcount\", \"genreid\" ]"
       "}"
     "}",
     "\"Audio.Fields.Song\": {"
@@ -434,7 +434,7 @@ namespace JSONRPC
                   "\"lyrics\", \"musicbrainztrackid\", \"musicbrainzartistid\","
                   "\"musicbrainzalbumid\", \"musicbrainzalbumartistid\","
                   "\"playcount\", \"fanart\", \"thumbnail\", \"file\","
-                  "\"albumid\", \"lastplayed\", \"disc\" ]"
+                  "\"albumid\", \"lastplayed\", \"disc\", \"genreid\" ]"
       "}"
     "}",
     "\"Audio.Details.Base\": {"
@@ -451,7 +451,8 @@ namespace JSONRPC
         "\"year\": { \"type\": \"integer\" },"
         "\"rating\": { \"type\": \"integer\" },"
         "\"musicbrainzalbumid\": { \"type\": \"string\" },"
-        "\"musicbrainzalbumartistid\": { \"type\": \"string\" }"
+        "\"musicbrainzalbumartistid\": { \"type\": \"string\" },"
+        "\"genreid\": { \"$ref\": \"Array.Integer\" }"
       "}"
     "}",
     "\"Audio.Details.Artist\": {"
@@ -1059,7 +1060,7 @@ namespace JSONRPC
                   "\"firstaired\", \"season\", \"episode\", \"showtitle\", \"thumbnail\", \"file\","
                   "\"resume\", \"artistid\", \"albumid\", \"tvshowid\", \"setid\", \"watchedepisodes\","
                   "\"disc\", \"tag\", \"art\", \"channel\", \"channeltype\", \"hidden\", \"locked\","
-                  "\"channelnumber\", \"starttime\", \"endtime\" ]"
+                  "\"channelnumber\", \"starttime\", \"endtime\", \"genreid\" ]"
       "}"
     "}",
     "\"List.Item.All\": {"
@@ -1086,7 +1087,7 @@ namespace JSONRPC
                   "\"runtime\", \"set\", \"showlink\", \"streamdetails\", \"top250\", \"votes\","
                   "\"firstaired\", \"season\", \"episode\", \"showtitle\", \"thumbnail\", \"file\","
                   "\"resume\", \"artistid\", \"albumid\", \"tvshowid\", \"setid\", \"watchedepisodes\","
-                  "\"disc\", \"tag\", \"art\", \"size\", \"lastmodified\", \"mimetype\" ]"
+                  "\"disc\", \"tag\", \"art\", \"size\", \"lastmodified\", \"mimetype\", \"genreid\" ]"
       "}"
     "}",
     "\"List.Item.File\": {"
index 612f6d7..227e9b5 100644 (file)
                 "theme", "mood", "style", "type", "albumlabel",
                 "rating", "year", "musicbrainzalbumid",
                 "musicbrainzalbumartistid", "fanart", "thumbnail",
-                "playcount" ]
+                "playcount", "genreid" ]
     }
   },
   "Audio.Fields.Song": {
                 "lyrics", "musicbrainztrackid", "musicbrainzartistid",
                 "musicbrainzalbumid", "musicbrainzalbumartistid",
                 "playcount", "fanart", "thumbnail", "file",
-                "albumid", "lastplayed", "disc" ]
+                "albumid", "lastplayed", "disc", "genreid" ]
     }
   },
   "Audio.Details.Base": {
       "year": { "type": "integer" },
       "rating": { "type": "integer" },
       "musicbrainzalbumid": { "type": "string" },
-      "musicbrainzalbumartistid": { "type": "string" }
+      "musicbrainzalbumartistid": { "type": "string" },
+      "genreid": { "$ref": "Array.Integer" }
     }
   },
   "Audio.Details.Artist": {
                 "firstaired", "season", "episode", "showtitle", "thumbnail", "file",
                 "resume", "artistid", "albumid", "tvshowid", "setid", "watchedepisodes",
                 "disc", "tag", "art", "channel", "channeltype", "hidden", "locked",
-                "channelnumber", "starttime", "endtime" ]
+                "channelnumber", "starttime", "endtime", "genreid" ]
     }
   },
   "List.Item.All": {
                 "runtime", "set", "showlink", "streamdetails", "top250", "votes",
                 "firstaired", "season", "episode", "showtitle", "thumbnail", "file",
                 "resume", "artistid", "albumid", "tvshowid", "setid", "watchedepisodes",
-                "disc", "tag", "art", "size", "lastmodified", "mimetype" ]
+                "disc", "tag", "art", "size", "lastmodified", "mimetype", "genreid" ]
     }
   },
   "List.Item.File": {
index f9e99a5..0c825a8 100644 (file)
@@ -775,7 +775,65 @@ bool CMusicDatabase::GetArtistsBySong(int idSong, bool includeFeatured, std::vec
     CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idSong);
   }
   return false;
-};
+}
+
+bool CMusicDatabase::GetGenresByAlbum(int idAlbum, std::vector<int>& genres)
+{
+  try
+  {
+    CStdString strSQL = PrepareSQL("select idGenre from album_genre where idAlbum = %i ORDER BY iOrder ASC", idAlbum);
+    if (!m_pDS->query(strSQL.c_str()))
+      return false;
+    if (m_pDS->num_rows() == 0)
+    {
+      m_pDS->close();
+      return true;
+    }
+
+    while (!m_pDS->eof())
+    {
+      genres.push_back(m_pDS->fv("idGenre").get_asInt());
+      m_pDS->next();
+    }
+    m_pDS->close();
+
+    return true;
+  }
+  catch (...)
+  {
+    CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idAlbum);
+  }
+  return false;
+}
+
+bool CMusicDatabase::GetGenresBySong(int idSong, std::vector<int>& genres)
+{
+  try
+  {
+    CStdString strSQL = PrepareSQL("select idGenre from song_genre where idSong = %i ORDER BY iOrder ASC", idSong);
+    if (!m_pDS->query(strSQL.c_str()))
+      return false;
+    if (m_pDS->num_rows() == 0)
+    {
+      m_pDS->close();
+      return true;
+    }
+
+    while (!m_pDS->eof())
+    {
+      genres.push_back(m_pDS->fv("idGenre").get_asInt());
+      m_pDS->next();
+    }
+    m_pDS->close();
+
+    return true;
+  }
+  catch (...)
+  {
+    CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idSong);
+  }
+  return false;
+}
 
 int CMusicDatabase::AddPath(const CStdString& strPath1)
 {
index caad3ff..00b9027 100644 (file)
@@ -133,6 +133,9 @@ public:
   bool GetSongsByArtist(int idArtist, bool includeFeatured, std::vector<long>& songs);
   bool GetArtistsBySong(int idSong, bool includeFeatured, std::vector<long>& artists);
 
+  bool GetGenresByAlbum(int idAlbum, std::vector<int>& genres);
+  bool GetGenresBySong(int idSong, std::vector<int>& genres);
+
   bool GetTop100(const CStdString& strBaseDir, CFileItemList& items);
   bool GetTop100Albums(VECALBUMS& albums);
   bool GetTop100AlbumSongs(const CStdString& strBaseDir, CFileItemList& item);