From 5981f29dd64503f4d31cf63847134b699b61e7db Mon Sep 17 00:00:00 2001 From: Jonathan Marshall Date: Sun, 26 Feb 2012 20:22:51 +1300 Subject: smartplaylists that include other smartplaylists that include the first smartplaylist could cause infinite loops --- xbmc/PartyModeManager.cpp | 6 ++-- xbmc/filesystem/SmartPlaylistDirectory.cpp | 13 ++++---- xbmc/playlists/SmartPlayList.cpp | 50 +++++++++++++++++------------- xbmc/playlists/SmartPlayList.h | 12 ++++++- 4 files changed, 50 insertions(+), 31 deletions(-) diff --git a/xbmc/PartyModeManager.cpp b/xbmc/PartyModeManager.cpp index 26b7290224..ecfaf78b98 100644 --- a/xbmc/PartyModeManager.cpp +++ b/xbmc/PartyModeManager.cpp @@ -111,8 +111,9 @@ bool CPartyModeManager::Enable(PartyModeContext context /*= PARTYMODECONTEXT_MUS CMusicDatabase db; if (db.Open()) { + set playlists; if ( playlistLoaded ) - m_strCurrentFilterMusic = playlist.GetWhereClause(db); + m_strCurrentFilterMusic = playlist.GetWhereClause(db, playlists); CLog::Log(LOGINFO, "PARTY MODE MANAGER: Registering filter:[%s]", m_strCurrentFilterMusic.c_str()); m_iMatchingSongs = (int)db.GetSongIDs(m_strCurrentFilterMusic, songIDs); @@ -139,8 +140,9 @@ bool CPartyModeManager::Enable(PartyModeContext context /*= PARTYMODECONTEXT_MUS CVideoDatabase db; if (db.Open()) { + set playlists; if ( playlistLoaded ) - m_strCurrentFilterVideo = playlist.GetWhereClause(db); + m_strCurrentFilterVideo = playlist.GetWhereClause(db, playlists); CLog::Log(LOGINFO, "PARTY MODE MANAGER: Registering filter:[%s]", m_strCurrentFilterVideo.c_str()); m_iMatchingSongs += (int)db.GetMusicVideoIDs(m_strCurrentFilterVideo, songIDs2); diff --git a/xbmc/filesystem/SmartPlaylistDirectory.cpp b/xbmc/filesystem/SmartPlaylistDirectory.cpp index aa6668f888..45cf60756f 100644 --- a/xbmc/filesystem/SmartPlaylistDirectory.cpp +++ b/xbmc/filesystem/SmartPlaylistDirectory.cpp @@ -46,11 +46,12 @@ namespace XFILE if (!playlist.Load(strPath)) return false; bool success = false, success2 = false; + std::set playlists; if (playlist.GetType().Equals("tvshows")) { CVideoDatabase db; db.Open(); - CStdString whereOrder = playlist.GetWhereClause(db) + " " + playlist.GetOrderClause(db); + CStdString whereOrder = playlist.GetWhereClause(db, playlists) + " " + playlist.GetOrderClause(db); success = db.GetTvShowsByWhere("videodb://2/2/", whereOrder, items); items.SetContent("tvshows"); db.Close(); @@ -59,7 +60,7 @@ namespace XFILE { CVideoDatabase db; db.Open(); - CStdString whereOrder = playlist.GetWhereClause(db) + " " + playlist.GetOrderClause(db); + CStdString whereOrder = playlist.GetWhereClause(db, playlists) + " " + playlist.GetOrderClause(db); success = db.GetEpisodesByWhere("videodb://2/2/", whereOrder, items); items.SetContent("episodes"); db.Close(); @@ -68,7 +69,7 @@ namespace XFILE { CVideoDatabase db; db.Open(); - success = db.GetMoviesByWhere("videodb://1/2/", playlist.GetWhereClause(db), playlist.GetOrderClause(db), items, true); + success = db.GetMoviesByWhere("videodb://1/2/", playlist.GetWhereClause(db, playlists), playlist.GetOrderClause(db), items, true); items.SetContent("movies"); db.Close(); } @@ -76,7 +77,7 @@ namespace XFILE { CMusicDatabase db; db.Open(); - success = db.GetAlbumsByWhere("musicdb://3/", playlist.GetWhereClause(db), playlist.GetOrderClause(db), items); + success = db.GetAlbumsByWhere("musicdb://3/", playlist.GetWhereClause(db, playlists), playlist.GetOrderClause(db), items); items.SetContent("albums"); db.Close(); } @@ -90,7 +91,7 @@ namespace XFILE if (playlist.GetType().Equals("mixed")) playlist.SetType("songs"); - CStdString whereOrder = playlist.GetWhereClause(db) + " " + playlist.GetOrderClause(db); + CStdString whereOrder = playlist.GetWhereClause(db, playlists) + " " + playlist.GetOrderClause(db); success = db.GetSongsByWhere("", whereOrder, items); items.SetContent("songs"); db.Close(); @@ -103,7 +104,7 @@ namespace XFILE CStdString type=playlist.GetType(); if (playlist.GetType().Equals("mixed")) playlist.SetType("musicvideos"); - CStdString whereOrder = playlist.GetWhereClause(db) + " " + playlist.GetOrderClause(db); + CStdString whereOrder = playlist.GetWhereClause(db, playlists) + " " + playlist.GetOrderClause(db); CFileItemList items2; success2 = db.GetMusicVideosByWhere("videodb://3/2/", whereOrder, items2, false); // TODO: SMARTPLAYLISTS Don't check locks??? db.Close(); diff --git a/xbmc/playlists/SmartPlayList.cpp b/xbmc/playlists/SmartPlayList.cpp index f5d1ffa3a2..f99e519698 100644 --- a/xbmc/playlists/SmartPlayList.cpp +++ b/xbmc/playlists/SmartPlayList.cpp @@ -580,26 +580,6 @@ CStdString CSmartPlaylistRule::GetWhereClause(CDatabase &db, const CStdString& s query = "idFile" + negate + " in (select distinct idFile from streamdetails where strSubtitleLanguage " + parameter + ")"; else if (m_field == FIELD_VIDEOASPECT) query = "idFile" + negate + " in (select distinct idFile from streamdetails where fVideoAspect " + parameter + ")"; - else if (m_field == FIELD_PLAYLIST) - { // playlist field - grab our playlist and add to our where clause - CStdString playlistFile = CSmartPlaylistDirectory::GetPlaylistByName(m_parameter, strType); - if (!playlistFile.IsEmpty()) - { - CSmartPlaylist playlist; - playlist.Load(playlistFile); - CStdString playlistQuery; - // only playlists of same type will be part of the query - if (playlist.GetType().Equals(strType) || (playlist.GetType().Equals("mixed") && (strType == "songs" || strType == "musicvideos")) || playlist.GetType().IsEmpty()) - { - playlist.SetType(strType); - playlistQuery = playlist.GetWhereClause(db, false); - } - if (m_operator == OPERATOR_DOES_NOT_EQUAL && playlist.GetType().Equals(strType)) - query.Format("NOT (%s)", playlistQuery.c_str()); - else if (m_operator == OPERATOR_EQUALS && playlist.GetType().Equals(strType)) - query = playlistQuery; - } - } if (m_field == FIELD_PLAYCOUNT && strType != "songs" && strType != "albums") { // playcount is stored as NULL or number in video db if ((m_operator == OPERATOR_EQUALS && m_parameter == "0") || @@ -931,7 +911,7 @@ void CSmartPlaylist::AddRule(const CSmartPlaylistRule &rule) m_playlistRules.push_back(rule); } -CStdString CSmartPlaylist::GetWhereClause(CDatabase &db, bool needWhere /* = true */) +CStdString CSmartPlaylist::GetWhereClause(CDatabase &db, set &referencedPlaylists, bool needWhere /* = true */) { CStdString rule, currentRule; for (vector::iterator it = m_playlistRules.begin(); it != m_playlistRules.end(); ++it) @@ -941,7 +921,33 @@ CStdString CSmartPlaylist::GetWhereClause(CDatabase &db, bool needWhere /* = tru else if (needWhere) rule += "WHERE "; rule += "("; - currentRule = (*it).GetWhereClause(db, GetType()); + CStdString currentRule; + if (it->m_field == CSmartPlaylistRule::FIELD_PLAYLIST) + { + CStdString playlistFile = CSmartPlaylistDirectory::GetPlaylistByName(it->m_parameter, GetType()); + if (!playlistFile.IsEmpty() && referencedPlaylists.find(playlistFile) == referencedPlaylists.end()) + { + referencedPlaylists.insert(playlistFile); + CSmartPlaylist playlist; + playlist.Load(playlistFile); + CStdString playlistQuery; + // only playlists of same type will be part of the query + if (playlist.GetType().Equals(GetType()) || (playlist.GetType().Equals("mixed") && (GetType() == "songs" || GetType() == "musicvideos")) || playlist.GetType().IsEmpty()) + { + playlist.SetType(GetType()); + playlistQuery = playlist.GetWhereClause(db, referencedPlaylists, false); + } + if (playlist.GetType().Equals(GetType())) + { + if (it->m_operator == CSmartPlaylistRule::OPERATOR_DOES_NOT_EQUAL) + currentRule.Format("NOT (%s)", playlistQuery.c_str()); + else + currentRule = playlistQuery; + } + } + } + else + currentRule = (*it).GetWhereClause(db, GetType()); // if we don't get a rule, we add '1' or '0' so the query is still valid and doesn't fail if (currentRule.IsEmpty()) currentRule = m_matchAllRules ? "'1'" : "'0'"; diff --git a/xbmc/playlists/SmartPlayList.h b/xbmc/playlists/SmartPlayList.h index 5359a62aa5..4da982b642 100644 --- a/xbmc/playlists/SmartPlayList.h +++ b/xbmc/playlists/SmartPlayList.h @@ -23,6 +23,7 @@ #include "utils/StdString.h" #include "tinyXML/tinyxml.h" #include +#include class CDatabase; @@ -167,7 +168,16 @@ public: bool GetOrderAscending() const { return m_orderAscending; }; void AddRule(const CSmartPlaylistRule &rule); - CStdString GetWhereClause(CDatabase &db, bool needWhere = true); + + /*! \brief get the where clause for a playlist + We handle playlists inside playlists separately in order to ensure we don't introduce infinite loops + by playlist A including playlist B which also (perhaps via other playlists) then includes playlistA. + + \param db the database to use to format up results + \param referencedPlaylists a set of playlists to know when we reach a cycle + \param needWhere whether we need to prepend the where clause with "WHERE " + */ + CStdString GetWhereClause(CDatabase &db, std::set &referencedPlaylists, bool needWhere = true); CStdString GetOrderClause(CDatabase &db); const std::vector &GetRules() const; -- cgit v1.2.3