Skip to content
This repository

[GSoC] artist-based smartplaylists #1249

Merged
merged 2 commits into from over 1 year ago

3 participants

Sascha Montellese jmarshallnz night199uk
Sascha Montellese
Collaborator

This adds very basic support for artist-based smartplaylists. There are only very few possible rules i.e. artist, genre, moods, styles, born, bandformed, disbanded, died, biography, instruments and a compilation artist switch (not sure if this one makes sense I never really understood how that works). These rules could be extended if necessary.

Sascha Montellese
Collaborator

I extracted the changes to SmartPlaylist.cpp which were actually fixes for existing bugs (which nobody noticed so far it seems) and already pushed them to master.

@jmarshallnz or @night199uk could one of you shed some light on the implications of enabling/disabling "include artists who appear only on compilations"? Does it change the way the scraper works (i.e. it ignores those artists if enabled) or does it only change the way the SQL queries in CMusicDatabase::GetArtistsNav work (with the albumArtistsOnly parameter)? If the former holds true the "compilation artists" rule I added does not make any sense otherwise IMO it does.

jmarshallnz
Owner
Sascha Montellese
Collaborator

It's not an advanced setting it's a GUI setting in Settings -> Music -> Library. I always keep it disabled to get a clean list of artists but if I understood @night199uk right he plans to improve scraping/organization of all those "Foo feat. Bar" so it might make sense to just keep it on the SQL level i.e. grab the information for all the artists but in Music -> Artists only show the album artists. Then maybe add a new node Music -> Compilation artists where only those artists are shown.

Thinking about it I'll remove that rule/filter because I have neither the understanding for it nor the items/database to actually test it.

night199uk
Collaborator
Sascha Montellese
Collaborator

@night199uk: I've removed that part for now because I can't test it anyway. I was also confused by boolFeatured and bCompilation so I can still add it back once your musicdatabase changes/refactor have been merged as well.

Sascha Montellese
Collaborator

@cptspiff Thanks for the review and for spotting that oopsie. I fixed the issues you pointed out.

Sascha Montellese Montellese merged commit 5817696 into from August 10, 2012
Sascha Montellese Montellese closed this August 10, 2012
Sascha Montellese Montellese deleted the branch April 04, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
2  xbmc/dialogs/GUIDialogSmartPlaylistEditor.cpp
@@ -57,6 +57,7 @@ typedef struct
57 57
 
58 58
 static const translateType types[] = { { CGUIDialogSmartPlaylistEditor::TYPE_SONGS, "songs", 134 },
59 59
                                        { CGUIDialogSmartPlaylistEditor::TYPE_ALBUMS, "albums", 132 },
  60
+                                       { CGUIDialogSmartPlaylistEditor::TYPE_ARTISTS, "artists", 133 },
60 61
                                        { CGUIDialogSmartPlaylistEditor::TYPE_MIXED, "mixed", 20395 },
61 62
                                        { CGUIDialogSmartPlaylistEditor::TYPE_MUSICVIDEOS, "musicvideos", 20389 },
62 63
                                        { CGUIDialogSmartPlaylistEditor::TYPE_MOVIES, "movies", 20342 },
@@ -356,6 +357,7 @@ void CGUIDialogSmartPlaylistEditor::OnWindowLoaded()
356 357
   { // music types + mixed
357 358
     allowedTypes.push_back(TYPE_SONGS);
358 359
     allowedTypes.push_back(TYPE_ALBUMS);
  360
+    allowedTypes.push_back(TYPE_ARTISTS);
359 361
     allowedTypes.push_back(TYPE_MIXED);
360 362
   }
361 363
   else if (m_mode.Equals("video"))
2  xbmc/dialogs/GUIDialogSmartPlaylistEditor.h
@@ -30,7 +30,7 @@ class CGUIDialogSmartPlaylistEditor :
30 30
       public CGUIDialog
31 31
 {
32 32
 public:
33  
-  enum PLAYLIST_TYPE { TYPE_SONGS = 1, TYPE_ALBUMS, TYPE_MIXED, TYPE_MUSICVIDEOS, TYPE_MOVIES, TYPE_TVSHOWS, TYPE_EPISODES };
  33
+  enum PLAYLIST_TYPE { TYPE_SONGS = 1, TYPE_ALBUMS, TYPE_ARTISTS, TYPE_MIXED, TYPE_MUSICVIDEOS, TYPE_MOVIES, TYPE_TVSHOWS, TYPE_EPISODES };
34 34
 
35 35
   CGUIDialogSmartPlaylistEditor(void);
36 36
   virtual ~CGUIDialogSmartPlaylistEditor(void);
4  xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp
@@ -117,7 +117,7 @@ void CGUIDialogSmartPlaylistRule::OnBrowse()
117 117
   {
118 118
     if (m_type.Equals("tvshows") || m_type.Equals("episodes") || m_type.Equals("movies"))
119 119
       videodatabase.GetGenresNav("videodb://2/1/",items,type);
120  
-    else if (m_type.Equals("songs") || m_type.Equals("albums") || m_type.Equals("mixed"))
  120
+    else if (m_type.Equals("songs") || m_type.Equals("albums") || m_type.Equals("artists") || m_type.Equals("mixed"))
121 121
       database.GetGenresNav("musicdb://1/",items);
122 122
     if (m_type.Equals("musicvideos") || m_type.Equals("mixed"))
123 123
     {
@@ -134,7 +134,7 @@ void CGUIDialogSmartPlaylistRule::OnBrowse()
134 134
   }
135 135
   else if (m_rule.m_field == FieldArtist || m_rule.m_field == FieldAlbumArtist)
136 136
   {
137  
-    if (m_type.Equals("songs") || m_type.Equals("mixed") || m_type.Equals("albums"))
  137
+    if (m_type.Equals("songs") || m_type.Equals("mixed") || m_type.Equals("albums") || m_type.Equals("artists"))
138 138
       database.GetArtistsNav("musicdb://2/", items, m_rule.m_field == FieldAlbumArtist, -1);
139 139
     if (m_type.Equals("musicvideos") || m_type.Equals("mixed"))
140 140
     {
21  xbmc/filesystem/SmartPlaylistDirectory.cpp
@@ -120,6 +120,27 @@ namespace XFILE
120 120
         db.Close();
121 121
       }
122 122
     }
  123
+    else if (playlist.GetType().Equals("artists"))
  124
+    {
  125
+      CMusicDatabase db;
  126
+      if (db.Open())
  127
+      {
  128
+        CMusicDbUrl musicUrl;
  129
+        CStdString xsp;
  130
+
  131
+        if (!musicUrl.FromString("musicdb://2/") || !playlist.SaveAsJson(xsp, false))
  132
+          return false;
  133
+
  134
+        // store the smartplaylist as JSON in the URL as well
  135
+        musicUrl.AddOption("xsp", xsp);
  136
+
  137
+        CDatabase::Filter filter;
  138
+        success = db.GetArtistsByWhere(musicUrl.ToString(), filter, items, sorting);
  139
+        items.SetContent("albums");
  140
+        db.Close();
  141
+      }
  142
+    }
  143
+
123 144
     if (playlist.GetType().Equals("songs") || playlist.GetType().Equals("mixed") || playlist.GetType().IsEmpty())
124 145
     {
125 146
       CMusicDatabase db;
9  xbmc/interfaces/json-rpc/AudioLibrary.cpp
@@ -63,8 +63,13 @@ JSONRPC_STATUS CAudioLibrary::GetArtists(const CStdString &method, ITransportLay
63 63
   if (parameterObject["albumartistsonly"].isBoolean())
64 64
     albumArtistsOnly = parameterObject["albumartistsonly"].asBoolean();
65 65
 
  66
+  SortDescription sorting;
  67
+  ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
  68
+  if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
  69
+    return InvalidParams;
  70
+
66 71
   CFileItemList items;
67  
-  if (!musicdatabase.GetArtistsNav(musicUrl.ToString(), items, albumArtistsOnly, genreID, albumID, songID))
  72
+  if (!musicdatabase.GetArtistsNav(musicUrl.ToString(), items, albumArtistsOnly, genreID, albumID, songID, sorting))
68 73
     return InternalError;
69 74
 
70 75
   // Add "artist" to "properties" array by default
@@ -73,7 +78,7 @@ JSONRPC_STATUS CAudioLibrary::GetArtists(const CStdString &method, ITransportLay
73 78
     param["properties"] = CVariant(CVariant::VariantTypeArray);
74 79
   param["properties"].append("artist");
75 80
 
76  
-  HandleFileItemList("artistid", false, "artists", items, param, result);
  81
+  HandleFileItemList("artistid", false, "artists", items, param, result, false);
77 82
   return OK;
78 83
 }
79 84
 
129  xbmc/music/MusicDatabase.cpp
@@ -955,25 +955,30 @@ CAlbum CMusicDatabase::GetAlbumFromDataset(const dbiplus::sql_record* const reco
955 955
 
956 956
 CArtist CMusicDatabase::GetArtistFromDataset(dbiplus::Dataset* pDS, bool needThumb)
957 957
 {
  958
+  return GetArtistFromDataset(pDS->get_sql_record(), needThumb);
  959
+}
  960
+
  961
+CArtist CMusicDatabase::GetArtistFromDataset(const dbiplus::sql_record* const record, bool needThumb /* = true */)
  962
+{
958 963
   CArtist artist;
959  
-  artist.idArtist = pDS->fv(artist_idArtist).get_asInt();
960  
-  artist.strArtist = pDS->fv(artist_strArtist).get_asString();
961  
-  artist.genre = StringUtils::Split(pDS->fv(artist_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
962  
-  artist.strBiography = pDS->fv(artist_strBiography).get_asString();
963  
-  artist.styles = StringUtils::Split(pDS->fv(artist_strStyles).get_asString(), g_advancedSettings.m_musicItemSeparator);
964  
-  artist.moods = StringUtils::Split(pDS->fv(artist_strMoods).get_asString(), g_advancedSettings.m_musicItemSeparator);
965  
-  artist.strBorn = pDS->fv(artist_strBorn).get_asString();
966  
-  artist.strFormed = pDS->fv(artist_strFormed).get_asString();
967  
-  artist.strDied = pDS->fv(artist_strDied).get_asString();
968  
-  artist.strDisbanded = pDS->fv(artist_strDisbanded).get_asString();
969  
-  artist.yearsActive = StringUtils::Split(pDS->fv(artist_strYearsActive).get_asString(), g_advancedSettings.m_musicItemSeparator);
970  
-  artist.instruments = StringUtils::Split(pDS->fv(artist_strInstruments).get_asString(), g_advancedSettings.m_musicItemSeparator);
  964
+  artist.idArtist = record->at(artist_idArtist).get_asInt();
  965
+  artist.strArtist = record->at(artist_strArtist).get_asString();
  966
+  artist.genre = StringUtils::Split(record->at(artist_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
  967
+  artist.strBiography = record->at(artist_strBiography).get_asString();
  968
+  artist.styles = StringUtils::Split(record->at(artist_strStyles).get_asString(), g_advancedSettings.m_musicItemSeparator);
  969
+  artist.moods = StringUtils::Split(record->at(artist_strMoods).get_asString(), g_advancedSettings.m_musicItemSeparator);
  970
+  artist.strBorn = record->at(artist_strBorn).get_asString();
  971
+  artist.strFormed = record->at(artist_strFormed).get_asString();
  972
+  artist.strDied = record->at(artist_strDied).get_asString();
  973
+  artist.strDisbanded = record->at(artist_strDisbanded).get_asString();
  974
+  artist.yearsActive = StringUtils::Split(record->at(artist_strYearsActive).get_asString(), g_advancedSettings.m_musicItemSeparator);
  975
+  artist.instruments = StringUtils::Split(record->at(artist_strInstruments).get_asString(), g_advancedSettings.m_musicItemSeparator);
971 976
 
972 977
   if (needThumb)
973 978
   {
974  
-    artist.fanart.m_xml = pDS->fv(artist_strFanart).get_asString();
  979
+    artist.fanart.m_xml = record->at(artist_strFanart).get_asString();
975 980
     artist.fanart.Unpack();
976  
-    artist.thumbURL.ParseString(pDS->fv(artist_strImage).get_asString());
  981
+    artist.thumbURL.ParseString(record->at(artist_strImage).get_asString());
977 982
   }
978 983
 
979 984
   return artist;
@@ -2747,7 +2752,7 @@ bool CMusicDatabase::GetAlbumsByYear(const CStdString& strBaseDir, CFileItemList
2747 2752
   return GetAlbumsByWhere(musicUrl.ToString(), filter, items);
2748 2753
 }
2749 2754
 
2750  
-bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly /* = false */, int idGenre /* = -1 */, int idAlbum /* = -1 */, int idSong /* = -1 */)
  2755
+bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly /* = false */, int idGenre /* = -1 */, int idAlbum /* = -1 */, int idSong /* = -1 */, const SortDescription &sortDescription /* = SortDescription() */)
2751 2756
 {
2752 2757
   if (NULL == m_pDB.get()) return false;
2753 2758
   if (NULL == m_pDS.get()) return false;
@@ -2769,7 +2774,7 @@ bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList&
2769 2774
     musicUrl.AddOption("albumartistsonly", albumArtistsOnly);
2770 2775
 
2771 2776
     Filter filter;
2772  
-    bool result = GetArtistsByWhere(musicUrl.ToString(), filter, items);
  2777
+    bool result = GetArtistsByWhere(musicUrl.ToString(), filter, items, sortDescription);
2773 2778
     CLog::Log(LOGDEBUG,"Time to retrieve artists from dataset = %i", XbmcThreads::SystemClockMillis() - time);
2774 2779
 
2775 2780
     return result;
@@ -2782,20 +2787,49 @@ bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList&
2782 2787
   return false;
2783 2788
 }
2784 2789
 
2785  
-bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items)
  2790
+bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription /* = SortDescription() */)
2786 2791
 {
2787 2792
   if (NULL == m_pDB.get()) return false;
2788 2793
   if (NULL == m_pDS.get()) return false;
2789 2794
 
2790 2795
   try
2791 2796
   {
2792  
-    CStdString strSQL = PrepareSQL("select %s from artistview ", !filter.fields.empty() ? filter.fields.c_str() : "*");
  2797
+    int total = -1;
2793 2798
 
2794  
-    CMusicDbUrl musicUrl;
  2799
+    CStdString strSQL = "SELECT %s FROM artistview ";
  2800
+    
2795 2801
     Filter extFilter = filter;
2796  
-    if (!BuildSQL(strBaseDir, strSQL, extFilter, strSQL, musicUrl))
  2802
+    CMusicDbUrl musicUrl;
  2803
+    if (!musicUrl.FromString(strBaseDir) || !GetFilter(musicUrl, extFilter))
  2804
+      return false;
  2805
+
  2806
+    // if there are extra WHERE conditions we might need access
  2807
+    // to songview or albumview for these conditions
  2808
+    if (extFilter.where.size() > 0)
  2809
+    {
  2810
+      if (extFilter.where.find("songview") != string::npos)
  2811
+        extFilter.AppendJoin("JOIN song_artist ON song_artist.idArtist = artistview.idArtist JOIN songview ON songview.idSong = song_artist.idSong");
  2812
+      else if (extFilter.where.find("albumview") != string::npos)
  2813
+        extFilter.AppendJoin("JOIN album_artist ON album_artist.idArtist = artistview.idArtist JOIN albumview ON albumview.idAlbum = album_artist.idAlbum");
  2814
+
  2815
+      extFilter.AppendGroup("artistview.idArtist");
  2816
+    }
  2817
+    
  2818
+    CStdString strSQLExtra;
  2819
+    if (!BuildSQL(strSQLExtra, extFilter, strSQLExtra))
2797 2820
       return false;
2798 2821
 
  2822
+    // Apply the limiting directly here if there's no special sorting but limiting
  2823
+    if (extFilter.limit.empty() &&
  2824
+        sortDescription.sortBy == SortByNone &&
  2825
+       (sortDescription.limitStart > 0 || sortDescription.limitEnd > 0))
  2826
+    {
  2827
+      total = (int)strtol(GetSingleValue(PrepareSQL(strSQL, "COUNT(1)") + strSQLExtra, m_pDS).c_str(), NULL, 10);
  2828
+      strSQLExtra += DatabaseUtils::BuildLimitClause(sortDescription.limitEnd, sortDescription.limitStart);
  2829
+    }
  2830
+
  2831
+    strSQL = PrepareSQL(strSQL.c_str(), !extFilter.fields.empty() && extFilter.fields.compare("*") != 0 ? extFilter.fields.c_str() : "artistview.*") + strSQLExtra;
  2832
+
2799 2833
     // run query
2800 2834
     CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
2801 2835
     if (!m_pDS->query(strSQL.c_str())) return false;
@@ -2806,26 +2840,45 @@ bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filte
2806 2840
       return false;
2807 2841
     }
2808 2842
 
2809  
-    items.Reserve(iRowsFound);
  2843
+    // store the total value of items as a property
  2844
+    if (total < iRowsFound)
  2845
+      total = iRowsFound;
  2846
+    items.SetProperty("total", total);
  2847
+    
  2848
+    DatabaseResults results;
  2849
+    results.reserve(iRowsFound);
  2850
+    if (!SortUtils::SortFromDataset(sortDescription, MediaTypeArtist, m_pDS, results))
  2851
+      return false;
2810 2852
 
2811 2853
     // get data from returned rows
2812  
-    while (!m_pDS->eof())
  2854
+    items.Reserve(results.size());
  2855
+    const dbiplus::query_data &data = m_pDS->get_result_set().records;
  2856
+    for (DatabaseResults::const_iterator it = results.begin(); it != results.end(); it++)
2813 2857
     {
2814  
-      CArtist artist = GetArtistFromDataset(m_pDS.get(), false);
2815  
-      CFileItemPtr pItem(new CFileItem(artist));
2816  
-
2817  
-      CMusicDbUrl itemUrl = musicUrl;
2818  
-      CStdString path; path.Format("%ld/", artist.idArtist);
2819  
-      itemUrl.AppendPath(path);
2820  
-      pItem->SetPath(itemUrl.ToString());
  2858
+      unsigned int targetRow = (unsigned int)it->at(FieldRow).asInteger();
  2859
+      const dbiplus::sql_record* const record = data.at(targetRow);
  2860
+      
  2861
+      try
  2862
+      {
  2863
+        CArtist artist = GetArtistFromDataset(record, false);
  2864
+        CFileItemPtr pItem(new CFileItem(artist));
2821 2865
 
2822  
-      pItem->GetMusicInfoTag()->SetDatabaseId(artist.idArtist, "artist");
2823  
-      pItem->SetIconImage("DefaultArtist.png");
  2866
+        CMusicDbUrl itemUrl = musicUrl;
  2867
+        CStdString path; path.Format("%ld/", artist.idArtist);
  2868
+        itemUrl.AppendPath(path);
  2869
+        pItem->SetPath(itemUrl.ToString());
2824 2870
 
2825  
-      SetPropertiesFromArtist(*pItem,artist);
2826  
-      items.Add(pItem);
  2871
+        pItem->GetMusicInfoTag()->SetDatabaseId(artist.idArtist, "artist");
  2872
+        pItem->SetIconImage("DefaultArtist.png");
2827 2873
 
2828  
-      m_pDS->next();
  2874
+        SetPropertiesFromArtist(*pItem, artist);
  2875
+        items.Add(pItem);
  2876
+      }
  2877
+      catch (...)
  2878
+      {
  2879
+        m_pDS->close();
  2880
+        CLog::Log(LOGERROR, "%s - out of memory getting listing (got %i)", __FUNCTION__, items.Size());
  2881
+      }
2829 2882
     }
2830 2883
 
2831 2884
     // cleanup
@@ -5222,8 +5275,12 @@ bool CMusicDatabase::GetFilter(const CDbUrl &musicUrl, Filter &filter)
5222 5275
     if (!xsp.LoadFromJson(option->second.asString()))
5223 5276
       return false;
5224 5277
 
5225  
-    std::set<CStdString> playlists;
5226  
-    filter.AppendWhere(xsp.GetWhereClause(*this, playlists));
  5278
+    // check if the filter playlist matches the item type
  5279
+    if (xsp.GetType() != "artists"|| xsp.GetType()  == type)
  5280
+    {
  5281
+      std::set<CStdString> playlists;
  5282
+      filter.AppendWhere(xsp.GetWhereClause(*this, playlists));
  5283
+    }
5227 5284
   }
5228 5285
 
5229 5286
   return true;
7  xbmc/music/MusicDatabase.h
@@ -152,14 +152,14 @@ class CMusicDatabase : public CDatabase
152 152
   bool GetPathHash(const CStdString &path, CStdString &hash);
153 153
   bool GetGenresNav(const CStdString& strBaseDir, CFileItemList& items);
154 154
   bool GetYearsNav(const CStdString& strBaseDir, CFileItemList& items);
155  
-  bool GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly = false, int idGenre = -1, int idAlbum = -1, int idSong = -1);
  155
+  bool GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly = false, int idGenre = -1, int idAlbum = -1, int idSong = -1, const SortDescription &sortDescription = SortDescription());
156 156
   bool GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre = -1, int idArtist = -1, const SortDescription &sortDescription = SortDescription());
157 157
   bool GetAlbumsByYear(const CStdString &strBaseDir, CFileItemList& items, int year);
158 158
   bool GetSongsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idArtist,int idAlbum, const SortDescription &sortDescription = SortDescription());
159 159
   bool GetSongsByYear(const CStdString& baseDir, CFileItemList& items, int year);
160 160
   bool GetSongsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription());
161 161
   bool GetAlbumsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList &items, const SortDescription &sortDescription = SortDescription());
162  
-  bool GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items);
  162
+  bool GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription());
163 163
   bool GetRandomSong(CFileItem* item, int& idSong, const Filter &filter);
164 164
   int GetKaraokeSongsCount();
165 165
   int GetSongsCount(const Filter &filter = Filter());
@@ -299,7 +299,8 @@ class CMusicDatabase : public CDatabase
299 299
 
300 300
   void SplitString(const CStdString &multiString, std::vector<std::string> &vecStrings, CStdString &extraStrings);
301 301
   CSong GetSongFromDataset(bool bWithMusicDbPath=false);
302  
-  CArtist GetArtistFromDataset(dbiplus::Dataset* pDS, bool needThumb=true);
  302
+  CArtist GetArtistFromDataset(dbiplus::Dataset* pDS, bool needThumb = true);
  303
+  CArtist GetArtistFromDataset(const dbiplus::sql_record* const record, bool needThumb = true);
303 304
   CAlbum GetAlbumFromDataset(dbiplus::Dataset* pDS, bool imageURL=false);
304 305
   CAlbum GetAlbumFromDataset(const dbiplus::sql_record* const record, bool imageURL=false);
305 306
   void GetFileItemFromDataset(CFileItem* item, const CStdString& strMusicDBbasePath);
33  xbmc/playlists/SmartPlayList.cpp
@@ -102,7 +102,13 @@ static const translateField fields[] = {
102 102
   { "subtitlelanguage",  FieldSubtitleLanguage,        SortBySubtitleLanguage,         CSmartPlaylistRule::TEXTIN_FIELD,     21448 },
103 103
   { "random",            FieldRandom,                  SortByRandom,                   CSmartPlaylistRule::TEXT_FIELD,       590 },
104 104
   { "playlist",          FieldPlaylist,                SortByPlaylistOrder,            CSmartPlaylistRule::PLAYLIST_FIELD,   559 },
105  
-  { "tag",               FieldTag,                     SortByNone,                     CSmartPlaylistRule::BROWSEABLE_FIELD, 20459 }
  105
+  { "tag",               FieldTag,                     SortByNone,                     CSmartPlaylistRule::BROWSEABLE_FIELD, 20459 },
  106
+  { "instruments",       FieldInstruments,             SortByNone,                     CSmartPlaylistRule::TEXT_FIELD,       21892 },
  107
+  { "biography",         FieldBiography,               SortByNone,                     CSmartPlaylistRule::TEXT_FIELD,       21887 },
  108
+  { "born",              FieldBorn,                    SortByNone,                     CSmartPlaylistRule::TEXT_FIELD,       21893 },
  109
+  { "bandformed",        FieldBandFormed,              SortByNone,                     CSmartPlaylistRule::TEXT_FIELD,       21894 },
  110
+  { "disbanded",         FieldDisbanded,               SortByNone,                     CSmartPlaylistRule::TEXT_FIELD,       21896 },
  111
+  { "died",              FieldDied,                    SortByNone,                     CSmartPlaylistRule::TEXT_FIELD,       21897 }
106 112
 };
107 113
 
108 114
 #define NUM_FIELDS sizeof(fields) / sizeof(translateField)
@@ -214,8 +220,8 @@ bool CSmartPlaylistRule::Load(const CVariant &obj)
214 220
   if (m_operator == OPERATOR_TRUE || m_operator == OPERATOR_FALSE)
215 221
     return true;
216 222
 
217  
-   if (!obj.isMember("value") || (!obj["value"].isString() && !obj["value"].isArray()))
218  
-     return false;
  223
+  if (!obj.isMember("value") || (!obj["value"].isString() && !obj["value"].isArray()))
  224
+    return false;
219 225
 
220 226
   const CVariant &value = obj["value"];
221 227
   if (value.isString() && !value.asString().empty())
@@ -373,6 +379,19 @@ vector<Field> CSmartPlaylistRule::GetFields(const CStdString &type)
373 379
     fields.push_back(FieldMusicLabel);
374 380
     fields.push_back(FieldRating);
375 381
   }
  382
+  else if (type == "artists")
  383
+  {
  384
+    fields.push_back(FieldArtist);
  385
+    fields.push_back(FieldGenre);
  386
+    fields.push_back(FieldMoods);
  387
+    fields.push_back(FieldStyles);
  388
+    fields.push_back(FieldInstruments);
  389
+    fields.push_back(FieldBiography);
  390
+    fields.push_back(FieldBorn);
  391
+    fields.push_back(FieldBandFormed);
  392
+    fields.push_back(FieldDisbanded);
  393
+    fields.push_back(FieldDied);
  394
+  }
376 395
   else if (type == "tvshows")
377 396
   {
378 397
     fields.push_back(FieldTitle);
@@ -512,6 +531,10 @@ std::vector<SortBy> CSmartPlaylistRule::GetOrders(const CStdString &type)
512 531
     //orders.push_back(SortByMusicLabel);
513 532
     orders.push_back(SortByRating);
514 533
   }
  534
+  else if (type == "artists")
  535
+  {
  536
+    orders.push_back(SortByArtist);
  537
+  }
515 538
   else if (type == "tvshows")
516 539
   {
517 540
     orders.push_back(SortBySortTitle);
@@ -693,7 +716,7 @@ CStdString CSmartPlaylistRule::GetWhereClause(const CDatabase &db, const CStdStr
693 716
     if (strType == "movies")
694 717
     {
695 718
       if (m_field == FieldInProgress)
696  
-        return "movieview.idFile " + negate + " in (select idFile from bookmark where type = 1)";
  719
+        return "movieview.idFile " + negate + " IN (select idFile from bookmark where type = 1)";
697 720
       else if (m_field == FieldTrailer)
698 721
         return negate + GetField(m_field, strType) + "!= ''";
699 722
     }
@@ -1250,7 +1273,7 @@ const vector<CSmartPlaylistRule> &CSmartPlaylist::GetRules() const
1250 1273
 
1251 1274
 CStdString CSmartPlaylist::GetSaveLocation() const
1252 1275
 {
1253  
-  if (m_playlistType == "songs" || m_playlistType == "albums")
  1276
+  if (m_playlistType == "songs" || m_playlistType == "albums" || m_playlistType == "artists")
1254 1277
     return "music";
1255 1278
   else if (m_playlistType == "mixed")
1256 1279
     return "mixed";
37  xbmc/utils/DatabaseUtils.cpp
@@ -125,6 +125,20 @@ std::string DatabaseUtils::GetField(Field field, MediaType mediaType, DatabaseQu
125 125
     else if (field == FieldGenre) return "songview.strGenre";
126 126
     else if (field == FieldDateAdded && queryPart == DatabaseQueryPartOrderBy) return "songview.idSong";     // only used for order clauses
127 127
   }
  128
+  else if (mediaType == MediaTypeArtist)
  129
+  {
  130
+    if (field == FieldId) return "artistview.idArtist";
  131
+    else if (field == FieldArtist) return "artistview.strArtist";
  132
+    else if (field == FieldGenre) return "artistview.strGenres";
  133
+    else if (field == FieldMoods) return "artistview.strMoods";
  134
+    else if (field == FieldStyles) return "artistview.strStyles";
  135
+    else if (field == FieldInstruments) return "artistview.strInstruments";
  136
+    else if (field == FieldBiography) return "artistview.strBiography";
  137
+    else if (field == FieldBorn) return "artistview.strBorn";
  138
+    else if (field == FieldBandFormed) return "artistview.strFormed";
  139
+    else if (field == FieldDisbanded) return "artistview.strDisbanded";
  140
+    else if (field == FieldDied) return "artistview.strDied";
  141
+  }
128 142
   else if (mediaType == MediaTypeMusicVideo)
129 143
   {
130 144
     CStdString result;
@@ -299,6 +313,20 @@ int DatabaseUtils::GetFieldIndex(Field field, MediaType mediaType)
299 313
     else if (field == FieldGenre) return CMusicDatabase::song_strGenres;
300 314
     else if (field == FieldArtist || field == FieldAlbumArtist) return CMusicDatabase::song_strArtists;
301 315
   }
  316
+  else if (mediaType == MediaTypeArtist)
  317
+  {
  318
+    if (field == FieldId) return CMusicDatabase::artist_idArtist;
  319
+    else if (field == FieldArtist) return CMusicDatabase::artist_strArtist;
  320
+    else if (field == FieldGenre) return CMusicDatabase::artist_strGenres;
  321
+    else if (field == FieldMoods) return CMusicDatabase::artist_strMoods;
  322
+    else if (field == FieldStyles) return CMusicDatabase::artist_strStyles;
  323
+    else if (field == FieldInstruments) return CMusicDatabase::artist_strInstruments;
  324
+    else if (field == FieldBiography) return CMusicDatabase::artist_strBiography;
  325
+    else if (field == FieldBorn) return CMusicDatabase::artist_strBorn;
  326
+    else if (field == FieldBandFormed) return CMusicDatabase::artist_strFormed;
  327
+    else if (field == FieldDisbanded) return CMusicDatabase::artist_strDisbanded;
  328
+    else if (field == FieldDied) return CMusicDatabase::artist_strDied;
  329
+  }
302 330
   else if (mediaType == MediaTypeMusicVideo)
303 331
   {
304 332
     if (field == FieldId) return 0;
@@ -325,8 +353,7 @@ int DatabaseUtils::GetFieldIndex(Field field, MediaType mediaType)
325 353
     // the first field is the item's ID and the second is the item's file ID
326 354
     index += 2;
327 355
   }
328  
-  else
329  
-  if (mediaType == MediaTypeMovie)
  356
+  else if (mediaType == MediaTypeMovie)
330 357
   {
331 358
     if (field == FieldId) return 0;
332 359
     else if (field == FieldTitle) index = VIDEODB_ID_TITLE;
@@ -440,6 +467,8 @@ bool DatabaseUtils::GetSelectFields(const Fields &fields, MediaType mediaType, F
440 467
     sortFields.insert(FieldAlbum);
441 468
   else if (mediaType == MediaTypeSong)
442 469
     sortFields.insert(FieldTrackNumber);
  470
+  else if (mediaType == MediaTypeArtist)
  471
+    sortFields.insert(FieldArtist);
443 472
 
444 473
   selectFields.clear();
445 474
   for (Fields::const_iterator it = sortFields.begin(); it != sortFields.end(); it++)
@@ -603,6 +632,10 @@ bool DatabaseUtils::GetDatabaseResults(MediaType mediaType, const FieldList &fie
603 632
       break;
604 633
     }
605 634
 
  635
+    case MediaTypeArtist:
  636
+      result[FieldLabel] = result.at(FieldArtist).asString();
  637
+      break;
  638
+
606 639
     default:
607 640
       break;
608 641
     }
8  xbmc/utils/DatabaseUtils.h
@@ -110,7 +110,13 @@ typedef enum {
110 110
   FieldAudioLanguage,
111 111
   FieldSubtitleLanguage,
112 112
   FieldProductionCode,
113  
-  FieldTag
  113
+  FieldTag,
  114
+  FieldInstruments,
  115
+  FieldBiography,
  116
+  FieldBorn,
  117
+  FieldBandFormed,
  118
+  FieldDisbanded,
  119
+  FieldDied
114 120
 } Field;
115 121
 
116 122
 typedef std::set<Field> Fields;
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.