diff options
Diffstat (limited to 'xbmc/favourites/FavouritesService.cpp')
-rw-r--r-- | xbmc/favourites/FavouritesService.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/xbmc/favourites/FavouritesService.cpp b/xbmc/favourites/FavouritesService.cpp new file mode 100644 index 0000000..8659445 --- /dev/null +++ b/xbmc/favourites/FavouritesService.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FavouritesService.h" + +#include "FileItem.h" +#include "GUIPassword.h" +#include "ServiceBroker.h" +#include "Util.h" +#include "favourites/FavouritesURL.h" +#include "profiles/ProfileManager.h" +#include "settings/SettingsComponent.h" +#include "utils/ContentUtils.h" +#include "utils/FileUtils.h" +#include "utils/URIUtils.h" +#include "utils/XBMCTinyXML.h" +#include "utils/log.h" + +#include <mutex> + +namespace +{ +bool IsMediasourceOfFavItemUnlocked(const std::shared_ptr<CFileItem>& item) +{ + if (!item) + { + CLog::Log(LOGERROR, "{}: No item passed (nullptr).", __func__); + return true; + } + + if (!item->IsFavourite()) + { + CLog::Log(LOGERROR, "{}: Wrong item passed (not a favourite).", __func__); + return true; + } + + const auto settingsComponent = CServiceBroker::GetSettingsComponent(); + if (!settingsComponent) + { + CLog::Log(LOGERROR, "{}: returned nullptr.", __func__); + return true; + } + + const auto profileManager = settingsComponent->GetProfileManager(); + if (!profileManager) + { + CLog::Log(LOGERROR, "{}: returned nullptr.", __func__); + return true; + } + + const CFavouritesURL url(item->GetPath()); + if (!url.IsValid()) + { + CLog::Log(LOGERROR, "{}: Invalid exec string (syntax error).", __func__); + return true; + } + + const CFavouritesURL::Action action = url.GetAction(); + + if (action != CFavouritesURL::Action::PLAY_MEDIA && + action != CFavouritesURL::Action::SHOW_PICTURE) + return true; + + const CFileItem itemToCheck(url.GetTarget(), url.IsDir()); + + if (action == CFavouritesURL::Action::PLAY_MEDIA) + { + if (itemToCheck.IsVideo()) + { + if (!profileManager->GetCurrentProfile().videoLocked()) + return g_passwordManager.IsMediaFileUnlocked("video", itemToCheck.GetPath()); + + return false; + } + else if (itemToCheck.IsAudio()) + { + if (!profileManager->GetCurrentProfile().musicLocked()) + return g_passwordManager.IsMediaFileUnlocked("music", itemToCheck.GetPath()); + + return false; + } + } + else if (action == CFavouritesURL::Action::SHOW_PICTURE && itemToCheck.IsPicture()) + { + if (!profileManager->GetCurrentProfile().picturesLocked()) + return g_passwordManager.IsMediaFileUnlocked("pictures", itemToCheck.GetPath()); + + return false; + } + + return true; +} + +bool LoadFromFile(const std::string& strPath, CFileItemList& items) +{ + CXBMCTinyXML doc; + if (!doc.LoadFile(strPath)) + { + CLog::Log(LOGERROR, "Unable to load {} (row {} column {})", strPath, doc.Row(), doc.Column()); + return false; + } + TiXmlElement *root = doc.RootElement(); + if (!root || strcmp(root->Value(), "favourites")) + { + CLog::Log(LOGERROR, "Favourites.xml doesn't contain the <favourites> root element"); + return false; + } + + TiXmlElement *favourite = root->FirstChildElement("favourite"); + while (favourite) + { + // format: + // <favourite name="Cool Video" thumb="foo.jpg">PlayMedia(c:\videos\cool_video.avi)</favourite> + // <favourite name="My Album" thumb="bar.tbn">ActivateWindow(MyMusic,c:\music\my album)</favourite> + // <favourite name="Apple Movie Trailers" thumb="path_to_thumb.png">RunScript(special://xbmc/scripts/apple movie trailers/default.py)</favourite> + const char *name = favourite->Attribute("name"); + const char *thumb = favourite->Attribute("thumb"); + if (name && favourite->FirstChild()) + { + const std::string favURL( + CFavouritesURL(CExecString(favourite->FirstChild()->Value())).GetURL()); + if (!items.Contains(favURL)) + { + const CFileItemPtr item(std::make_shared<CFileItem>(name)); + item->SetPath(favURL); + if (thumb) + item->SetArt("thumb", thumb); + items.Add(item); + } + } + favourite = favourite->NextSiblingElement("favourite"); + } + return true; +} +} // unnamed namespace + +CFavouritesService::CFavouritesService(std::string userDataFolder) : m_favourites("favourites://") +{ + ReInit(std::move(userDataFolder)); +} + +void CFavouritesService::ReInit(std::string userDataFolder) +{ + m_userDataFolder = std::move(userDataFolder); + m_favourites.Clear(); + m_favourites.SetContent("favourites"); + + std::string favourites = "special://xbmc/system/favourites.xml"; + if (CFileUtils::Exists(favourites)) + LoadFromFile(favourites, m_favourites); + else + CLog::Log(LOGDEBUG, "CFavourites::Load - no system favourites found, skipping"); + + favourites = URIUtils::AddFileToFolder(m_userDataFolder, "favourites.xml"); + if (CFileUtils::Exists(favourites)) + LoadFromFile(favourites, m_favourites); + else + CLog::Log(LOGDEBUG, "CFavourites::Load - no userdata favourites found, skipping"); +} + +bool CFavouritesService::Persist() +{ + CXBMCTinyXML doc; + TiXmlElement xmlRootElement("favourites"); + TiXmlNode *rootNode = doc.InsertEndChild(xmlRootElement); + if (!rootNode) + return false; + + for (const auto& item : m_favourites) + { + TiXmlElement favNode("favourite"); + favNode.SetAttribute("name", item->GetLabel().c_str()); + if (item->HasArt("thumb")) + favNode.SetAttribute("thumb", item->GetArt("thumb").c_str()); + + TiXmlText execute(CFavouritesURL(item->GetPath()).GetExecString()); + favNode.InsertEndChild(execute); + rootNode->InsertEndChild(favNode); + } + + auto path = URIUtils::AddFileToFolder(m_userDataFolder, "favourites.xml"); + return doc.SaveFile(path); +} + +bool CFavouritesService::Save(const CFileItemList& items) +{ + { + std::unique_lock<CCriticalSection> lock(m_criticalSection); + m_favourites.Clear(); + m_favourites.Copy(items); + Persist(); + } + OnUpdated(); + return true; +} + +void CFavouritesService::OnUpdated() +{ + m_events.Publish(FavouritesUpdated{}); +} + +std::string CFavouritesService::GetFavouritesUrl(const CFileItem& item, int contextWindow) const +{ + return CFavouritesURL(item, contextWindow).GetURL(); +} + +bool CFavouritesService::AddOrRemove(const CFileItem& item, int contextWindow) +{ + auto favUrl = GetFavouritesUrl(item, contextWindow); + { + std::unique_lock<CCriticalSection> lock(m_criticalSection); + CFileItemPtr match = m_favourites.Get(favUrl); + if (match) + { // remove the item + m_favourites.Remove(match.get()); + } + else + { // create our new favourite item + const CFileItemPtr favourite(std::make_shared<CFileItem>(item.GetLabel())); + if (item.GetLabel().empty()) + favourite->SetLabel(CUtil::GetTitleFromPath(item.GetPath(), item.m_bIsFolder)); + favourite->SetArt("thumb", ContentUtils::GetPreferredArtImage(item)); + favourite->SetPath(favUrl); + m_favourites.Add(favourite); + } + Persist(); + } + OnUpdated(); + return true; +} + +bool CFavouritesService::IsFavourited(const CFileItem& item, int contextWindow) const +{ + std::unique_lock<CCriticalSection> lock(m_criticalSection); + return m_favourites.Contains(GetFavouritesUrl(item, contextWindow)); +} + +void CFavouritesService::GetAll(CFileItemList& items) const +{ + std::unique_lock<CCriticalSection> lock(m_criticalSection); + items.Clear(); + if (g_passwordManager.IsMasterLockUnlocked(false)) // don't prompt + { + items.Copy(m_favourites, true); // copy items + } + else + { + for (const auto& fav : m_favourites) + { + if (IsMediasourceOfFavItemUnlocked(fav)) + items.Add(fav); + } + } + + int index = 0; + for (const auto& item : items) + { + const CFavouritesURL favURL(item->GetPath()); + item->SetProperty("favourite.action", favURL.GetActionLabel()); + item->SetProperty("favourite.provider", favURL.GetProviderLabel()); + item->SetProperty("favourite.index", index++); + } +} + +void CFavouritesService::RefreshFavourites() +{ + m_events.Publish(FavouritesUpdated{}); +} |