Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GSoC] artist-based smartplaylists #1249

Merged
merged 2 commits into from Aug 10, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions xbmc/dialogs/GUIDialogSmartPlaylistEditor.cpp
Expand Up @@ -57,6 +57,7 @@ typedef struct


static const translateType types[] = { { CGUIDialogSmartPlaylistEditor::TYPE_SONGS, "songs", 134 }, static const translateType types[] = { { CGUIDialogSmartPlaylistEditor::TYPE_SONGS, "songs", 134 },
{ CGUIDialogSmartPlaylistEditor::TYPE_ALBUMS, "albums", 132 }, { CGUIDialogSmartPlaylistEditor::TYPE_ALBUMS, "albums", 132 },
{ CGUIDialogSmartPlaylistEditor::TYPE_ARTISTS, "artists", 133 },
{ CGUIDialogSmartPlaylistEditor::TYPE_MIXED, "mixed", 20395 }, { CGUIDialogSmartPlaylistEditor::TYPE_MIXED, "mixed", 20395 },
{ CGUIDialogSmartPlaylistEditor::TYPE_MUSICVIDEOS, "musicvideos", 20389 }, { CGUIDialogSmartPlaylistEditor::TYPE_MUSICVIDEOS, "musicvideos", 20389 },
{ CGUIDialogSmartPlaylistEditor::TYPE_MOVIES, "movies", 20342 }, { CGUIDialogSmartPlaylistEditor::TYPE_MOVIES, "movies", 20342 },
Expand Down Expand Up @@ -356,6 +357,7 @@ void CGUIDialogSmartPlaylistEditor::OnWindowLoaded()
{ // music types + mixed { // music types + mixed
allowedTypes.push_back(TYPE_SONGS); allowedTypes.push_back(TYPE_SONGS);
allowedTypes.push_back(TYPE_ALBUMS); allowedTypes.push_back(TYPE_ALBUMS);
allowedTypes.push_back(TYPE_ARTISTS);
allowedTypes.push_back(TYPE_MIXED); allowedTypes.push_back(TYPE_MIXED);
} }
else if (m_mode.Equals("video")) else if (m_mode.Equals("video"))
Expand Down
2 changes: 1 addition & 1 deletion xbmc/dialogs/GUIDialogSmartPlaylistEditor.h
Expand Up @@ -30,7 +30,7 @@ class CGUIDialogSmartPlaylistEditor :
public CGUIDialog public CGUIDialog
{ {
public: public:
enum PLAYLIST_TYPE { TYPE_SONGS = 1, TYPE_ALBUMS, TYPE_MIXED, TYPE_MUSICVIDEOS, TYPE_MOVIES, TYPE_TVSHOWS, TYPE_EPISODES }; enum PLAYLIST_TYPE { TYPE_SONGS = 1, TYPE_ALBUMS, TYPE_ARTISTS, TYPE_MIXED, TYPE_MUSICVIDEOS, TYPE_MOVIES, TYPE_TVSHOWS, TYPE_EPISODES };


CGUIDialogSmartPlaylistEditor(void); CGUIDialogSmartPlaylistEditor(void);
virtual ~CGUIDialogSmartPlaylistEditor(void); virtual ~CGUIDialogSmartPlaylistEditor(void);
Expand Down
4 changes: 2 additions & 2 deletions xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp
Expand Up @@ -117,7 +117,7 @@ void CGUIDialogSmartPlaylistRule::OnBrowse()
{ {
if (m_type.Equals("tvshows") || m_type.Equals("episodes") || m_type.Equals("movies")) if (m_type.Equals("tvshows") || m_type.Equals("episodes") || m_type.Equals("movies"))
videodatabase.GetGenresNav("videodb://2/1/",items,type); videodatabase.GetGenresNav("videodb://2/1/",items,type);
else if (m_type.Equals("songs") || m_type.Equals("albums") || m_type.Equals("mixed")) else if (m_type.Equals("songs") || m_type.Equals("albums") || m_type.Equals("artists") || m_type.Equals("mixed"))
database.GetGenresNav("musicdb://1/",items); database.GetGenresNav("musicdb://1/",items);
if (m_type.Equals("musicvideos") || m_type.Equals("mixed")) if (m_type.Equals("musicvideos") || m_type.Equals("mixed"))
{ {
Expand All @@ -134,7 +134,7 @@ void CGUIDialogSmartPlaylistRule::OnBrowse()
} }
else if (m_rule.m_field == FieldArtist || m_rule.m_field == FieldAlbumArtist) else if (m_rule.m_field == FieldArtist || m_rule.m_field == FieldAlbumArtist)
{ {
if (m_type.Equals("songs") || m_type.Equals("mixed") || m_type.Equals("albums")) if (m_type.Equals("songs") || m_type.Equals("mixed") || m_type.Equals("albums") || m_type.Equals("artists"))
database.GetArtistsNav("musicdb://2/", items, m_rule.m_field == FieldAlbumArtist, -1); database.GetArtistsNav("musicdb://2/", items, m_rule.m_field == FieldAlbumArtist, -1);
if (m_type.Equals("musicvideos") || m_type.Equals("mixed")) if (m_type.Equals("musicvideos") || m_type.Equals("mixed"))
{ {
Expand Down
21 changes: 21 additions & 0 deletions xbmc/filesystem/SmartPlaylistDirectory.cpp
Expand Up @@ -120,6 +120,27 @@ namespace XFILE
db.Close(); db.Close();
} }
} }
else if (playlist.GetType().Equals("artists"))
{
CMusicDatabase db;
if (db.Open())
{
CMusicDbUrl musicUrl;
CStdString xsp;

if (!musicUrl.FromString("musicdb://2/") || !playlist.SaveAsJson(xsp, false))
return false;

// store the smartplaylist as JSON in the URL as well
musicUrl.AddOption("xsp", xsp);

CDatabase::Filter filter;
success = db.GetArtistsByWhere(musicUrl.ToString(), filter, items, sorting);
items.SetContent("albums");
db.Close();
}
}

if (playlist.GetType().Equals("songs") || playlist.GetType().Equals("mixed") || playlist.GetType().IsEmpty()) if (playlist.GetType().Equals("songs") || playlist.GetType().Equals("mixed") || playlist.GetType().IsEmpty())
{ {
CMusicDatabase db; CMusicDatabase db;
Expand Down
9 changes: 7 additions & 2 deletions xbmc/interfaces/json-rpc/AudioLibrary.cpp
Expand Up @@ -63,8 +63,13 @@ JSONRPC_STATUS CAudioLibrary::GetArtists(const CStdString &method, ITransportLay
if (parameterObject["albumartistsonly"].isBoolean()) if (parameterObject["albumartistsonly"].isBoolean())
albumArtistsOnly = parameterObject["albumartistsonly"].asBoolean(); albumArtistsOnly = parameterObject["albumartistsonly"].asBoolean();


SortDescription sorting;
ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
return InvalidParams;

CFileItemList items; CFileItemList items;
if (!musicdatabase.GetArtistsNav(musicUrl.ToString(), items, albumArtistsOnly, genreID, albumID, songID)) if (!musicdatabase.GetArtistsNav(musicUrl.ToString(), items, albumArtistsOnly, genreID, albumID, songID, sorting))
return InternalError; return InternalError;


// Add "artist" to "properties" array by default // Add "artist" to "properties" array by default
Expand All @@ -73,7 +78,7 @@ JSONRPC_STATUS CAudioLibrary::GetArtists(const CStdString &method, ITransportLay
param["properties"] = CVariant(CVariant::VariantTypeArray); param["properties"] = CVariant(CVariant::VariantTypeArray);
param["properties"].append("artist"); param["properties"].append("artist");


HandleFileItemList("artistid", false, "artists", items, param, result); HandleFileItemList("artistid", false, "artists", items, param, result, false);
return OK; return OK;
} }


Expand Down
129 changes: 93 additions & 36 deletions xbmc/music/MusicDatabase.cpp
Expand Up @@ -954,26 +954,31 @@ CAlbum CMusicDatabase::GetAlbumFromDataset(const dbiplus::sql_record* const reco
} }


CArtist CMusicDatabase::GetArtistFromDataset(dbiplus::Dataset* pDS, bool needThumb) CArtist CMusicDatabase::GetArtistFromDataset(dbiplus::Dataset* pDS, bool needThumb)
{
return GetArtistFromDataset(pDS->get_sql_record(), needThumb);
}

CArtist CMusicDatabase::GetArtistFromDataset(const dbiplus::sql_record* const record, bool needThumb /* = true */)
{ {
CArtist artist; CArtist artist;
artist.idArtist = pDS->fv(artist_idArtist).get_asInt(); artist.idArtist = record->at(artist_idArtist).get_asInt();
artist.strArtist = pDS->fv(artist_strArtist).get_asString(); artist.strArtist = record->at(artist_strArtist).get_asString();
artist.genre = StringUtils::Split(pDS->fv(artist_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator); artist.genre = StringUtils::Split(record->at(artist_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
artist.strBiography = pDS->fv(artist_strBiography).get_asString(); artist.strBiography = record->at(artist_strBiography).get_asString();
artist.styles = StringUtils::Split(pDS->fv(artist_strStyles).get_asString(), g_advancedSettings.m_musicItemSeparator); artist.styles = StringUtils::Split(record->at(artist_strStyles).get_asString(), g_advancedSettings.m_musicItemSeparator);
artist.moods = StringUtils::Split(pDS->fv(artist_strMoods).get_asString(), g_advancedSettings.m_musicItemSeparator); artist.moods = StringUtils::Split(record->at(artist_strMoods).get_asString(), g_advancedSettings.m_musicItemSeparator);
artist.strBorn = pDS->fv(artist_strBorn).get_asString(); artist.strBorn = record->at(artist_strBorn).get_asString();
artist.strFormed = pDS->fv(artist_strFormed).get_asString(); artist.strFormed = record->at(artist_strFormed).get_asString();
artist.strDied = pDS->fv(artist_strDied).get_asString(); artist.strDied = record->at(artist_strDied).get_asString();
artist.strDisbanded = pDS->fv(artist_strDisbanded).get_asString(); artist.strDisbanded = record->at(artist_strDisbanded).get_asString();
artist.yearsActive = StringUtils::Split(pDS->fv(artist_strYearsActive).get_asString(), g_advancedSettings.m_musicItemSeparator); artist.yearsActive = StringUtils::Split(record->at(artist_strYearsActive).get_asString(), g_advancedSettings.m_musicItemSeparator);
artist.instruments = StringUtils::Split(pDS->fv(artist_strInstruments).get_asString(), g_advancedSettings.m_musicItemSeparator); artist.instruments = StringUtils::Split(record->at(artist_strInstruments).get_asString(), g_advancedSettings.m_musicItemSeparator);


if (needThumb) if (needThumb)
{ {
artist.fanart.m_xml = pDS->fv(artist_strFanart).get_asString(); artist.fanart.m_xml = record->at(artist_strFanart).get_asString();
artist.fanart.Unpack(); artist.fanart.Unpack();
artist.thumbURL.ParseString(pDS->fv(artist_strImage).get_asString()); artist.thumbURL.ParseString(record->at(artist_strImage).get_asString());
} }


return artist; return artist;
Expand Down Expand Up @@ -2747,7 +2752,7 @@ bool CMusicDatabase::GetAlbumsByYear(const CStdString& strBaseDir, CFileItemList
return GetAlbumsByWhere(musicUrl.ToString(), filter, items); return GetAlbumsByWhere(musicUrl.ToString(), filter, items);
} }


bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly /* = false */, int idGenre /* = -1 */, int idAlbum /* = -1 */, int idSong /* = -1 */) bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly /* = false */, int idGenre /* = -1 */, int idAlbum /* = -1 */, int idSong /* = -1 */, const SortDescription &sortDescription /* = SortDescription() */)
{ {
if (NULL == m_pDB.get()) return false; if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS.get()) return false; if (NULL == m_pDS.get()) return false;
Expand All @@ -2769,7 +2774,7 @@ bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList&
musicUrl.AddOption("albumartistsonly", albumArtistsOnly); musicUrl.AddOption("albumartistsonly", albumArtistsOnly);


Filter filter; Filter filter;
bool result = GetArtistsByWhere(musicUrl.ToString(), filter, items); bool result = GetArtistsByWhere(musicUrl.ToString(), filter, items, sortDescription);
CLog::Log(LOGDEBUG,"Time to retrieve artists from dataset = %i", XbmcThreads::SystemClockMillis() - time); CLog::Log(LOGDEBUG,"Time to retrieve artists from dataset = %i", XbmcThreads::SystemClockMillis() - time);


return result; return result;
Expand All @@ -2782,20 +2787,49 @@ bool CMusicDatabase::GetArtistsNav(const CStdString& strBaseDir, CFileItemList&
return false; return false;
} }


bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items) bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription /* = SortDescription() */)
{ {
if (NULL == m_pDB.get()) return false; if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS.get()) return false; if (NULL == m_pDS.get()) return false;


try try
{ {
CStdString strSQL = PrepareSQL("select %s from artistview ", !filter.fields.empty() ? filter.fields.c_str() : "*"); int total = -1;


CMusicDbUrl musicUrl; CStdString strSQL = "SELECT %s FROM artistview ";

Filter extFilter = filter; Filter extFilter = filter;
if (!BuildSQL(strBaseDir, strSQL, extFilter, strSQL, musicUrl)) CMusicDbUrl musicUrl;
if (!musicUrl.FromString(strBaseDir) || !GetFilter(musicUrl, extFilter))
return false;

// if there are extra WHERE conditions we might need access
// to songview or albumview for these conditions
if (extFilter.where.size() > 0)
{
if (extFilter.where.find("songview") != string::npos)
extFilter.AppendJoin("JOIN song_artist ON song_artist.idArtist = artistview.idArtist JOIN songview ON songview.idSong = song_artist.idSong");
else if (extFilter.where.find("albumview") != string::npos)
extFilter.AppendJoin("JOIN album_artist ON album_artist.idArtist = artistview.idArtist JOIN albumview ON albumview.idAlbum = album_artist.idAlbum");

extFilter.AppendGroup("artistview.idArtist");
}

CStdString strSQLExtra;
if (!BuildSQL(strSQLExtra, extFilter, strSQLExtra))
return false; return false;


// Apply the limiting directly here if there's no special sorting but limiting
if (extFilter.limit.empty() &&
sortDescription.sortBy == SortByNone &&
(sortDescription.limitStart > 0 || sortDescription.limitEnd > 0))
{
total = (int)strtol(GetSingleValue(PrepareSQL(strSQL, "COUNT(1)") + strSQLExtra, m_pDS).c_str(), NULL, 10);
strSQLExtra += DatabaseUtils::BuildLimitClause(sortDescription.limitEnd, sortDescription.limitStart);
}

strSQL = PrepareSQL(strSQL.c_str(), !extFilter.fields.empty() && extFilter.fields.compare("*") != 0 ? extFilter.fields.c_str() : "artistview.*") + strSQLExtra;

// run query // run query
CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str()); CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
if (!m_pDS->query(strSQL.c_str())) return false; if (!m_pDS->query(strSQL.c_str())) return false;
Expand All @@ -2806,26 +2840,45 @@ bool CMusicDatabase::GetArtistsByWhere(const CStdString& strBaseDir, const Filte
return false; return false;
} }


items.Reserve(iRowsFound); // store the total value of items as a property
if (total < iRowsFound)
total = iRowsFound;
items.SetProperty("total", total);

DatabaseResults results;
results.reserve(iRowsFound);
if (!SortUtils::SortFromDataset(sortDescription, MediaTypeArtist, m_pDS, results))
return false;


// get data from returned rows // get data from returned rows
while (!m_pDS->eof()) items.Reserve(results.size());
const dbiplus::query_data &data = m_pDS->get_result_set().records;
for (DatabaseResults::const_iterator it = results.begin(); it != results.end(); it++)
{ {
CArtist artist = GetArtistFromDataset(m_pDS.get(), false); unsigned int targetRow = (unsigned int)it->at(FieldRow).asInteger();
CFileItemPtr pItem(new CFileItem(artist)); const dbiplus::sql_record* const record = data.at(targetRow);

CMusicDbUrl itemUrl = musicUrl; try
CStdString path; path.Format("%ld/", artist.idArtist); {
itemUrl.AppendPath(path); CArtist artist = GetArtistFromDataset(record, false);
pItem->SetPath(itemUrl.ToString()); CFileItemPtr pItem(new CFileItem(artist));


pItem->GetMusicInfoTag()->SetDatabaseId(artist.idArtist, "artist"); CMusicDbUrl itemUrl = musicUrl;
pItem->SetIconImage("DefaultArtist.png"); CStdString path; path.Format("%ld/", artist.idArtist);
itemUrl.AppendPath(path);
pItem->SetPath(itemUrl.ToString());


SetPropertiesFromArtist(*pItem,artist); pItem->GetMusicInfoTag()->SetDatabaseId(artist.idArtist, "artist");
items.Add(pItem); pItem->SetIconImage("DefaultArtist.png");


m_pDS->next(); SetPropertiesFromArtist(*pItem, artist);
items.Add(pItem);
}
catch (...)
{
m_pDS->close();
CLog::Log(LOGERROR, "%s - out of memory getting listing (got %i)", __FUNCTION__, items.Size());
}
} }


// cleanup // cleanup
Expand Down Expand Up @@ -5222,8 +5275,12 @@ bool CMusicDatabase::GetFilter(const CDbUrl &musicUrl, Filter &filter)
if (!xsp.LoadFromJson(option->second.asString())) if (!xsp.LoadFromJson(option->second.asString()))
return false; return false;


std::set<CStdString> playlists; // check if the filter playlist matches the item type
filter.AppendWhere(xsp.GetWhereClause(*this, playlists)); if (xsp.GetType() != "artists"|| xsp.GetType() == type)
{
std::set<CStdString> playlists;
filter.AppendWhere(xsp.GetWhereClause(*this, playlists));
}
} }


return true; return true;
Expand Down
7 changes: 4 additions & 3 deletions xbmc/music/MusicDatabase.h
Expand Up @@ -152,14 +152,14 @@ class CMusicDatabase : public CDatabase
bool GetPathHash(const CStdString &path, CStdString &hash); bool GetPathHash(const CStdString &path, CStdString &hash);
bool GetGenresNav(const CStdString& strBaseDir, CFileItemList& items); bool GetGenresNav(const CStdString& strBaseDir, CFileItemList& items);
bool GetYearsNav(const CStdString& strBaseDir, CFileItemList& items); bool GetYearsNav(const CStdString& strBaseDir, CFileItemList& items);
bool GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly = false, int idGenre = -1, int idAlbum = -1, int idSong = -1); bool GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly = false, int idGenre = -1, int idAlbum = -1, int idSong = -1, const SortDescription &sortDescription = SortDescription());
bool GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre = -1, int idArtist = -1, const SortDescription &sortDescription = SortDescription()); bool GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre = -1, int idArtist = -1, const SortDescription &sortDescription = SortDescription());
bool GetAlbumsByYear(const CStdString &strBaseDir, CFileItemList& items, int year); bool GetAlbumsByYear(const CStdString &strBaseDir, CFileItemList& items, int year);
bool GetSongsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idArtist,int idAlbum, const SortDescription &sortDescription = SortDescription()); bool GetSongsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idArtist,int idAlbum, const SortDescription &sortDescription = SortDescription());
bool GetSongsByYear(const CStdString& baseDir, CFileItemList& items, int year); bool GetSongsByYear(const CStdString& baseDir, CFileItemList& items, int year);
bool GetSongsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription()); bool GetSongsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription());
bool GetAlbumsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList &items, const SortDescription &sortDescription = SortDescription()); bool GetAlbumsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList &items, const SortDescription &sortDescription = SortDescription());
bool GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items); bool GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription());
bool GetRandomSong(CFileItem* item, int& idSong, const Filter &filter); bool GetRandomSong(CFileItem* item, int& idSong, const Filter &filter);
int GetKaraokeSongsCount(); int GetKaraokeSongsCount();
int GetSongsCount(const Filter &filter = Filter()); int GetSongsCount(const Filter &filter = Filter());
Expand Down Expand Up @@ -299,7 +299,8 @@ class CMusicDatabase : public CDatabase


void SplitString(const CStdString &multiString, std::vector<std::string> &vecStrings, CStdString &extraStrings); void SplitString(const CStdString &multiString, std::vector<std::string> &vecStrings, CStdString &extraStrings);
CSong GetSongFromDataset(bool bWithMusicDbPath=false); CSong GetSongFromDataset(bool bWithMusicDbPath=false);
CArtist GetArtistFromDataset(dbiplus::Dataset* pDS, bool needThumb=true); CArtist GetArtistFromDataset(dbiplus::Dataset* pDS, bool needThumb = true);
CArtist GetArtistFromDataset(const dbiplus::sql_record* const record, bool needThumb = true);
CAlbum GetAlbumFromDataset(dbiplus::Dataset* pDS, bool imageURL=false); CAlbum GetAlbumFromDataset(dbiplus::Dataset* pDS, bool imageURL=false);
CAlbum GetAlbumFromDataset(const dbiplus::sql_record* const record, bool imageURL=false); CAlbum GetAlbumFromDataset(const dbiplus::sql_record* const record, bool imageURL=false);
void GetFileItemFromDataset(CFileItem* item, const CStdString& strMusicDBbasePath); void GetFileItemFromDataset(CFileItem* item, const CStdString& strMusicDBbasePath);
Expand Down