Merge pull request #4676 from jmarshallnz/dont_set_scraper_on_tvshow_on_nfo
[vuplus_xbmc] / xbmc / utils / RssManager.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "RssManager.h"
22 #include "addons/AddonInstaller.h"
23 #include "addons/AddonManager.h"
24 #include "dialogs/GUIDialogYesNo.h"
25 #include "filesystem/File.h"
26 #include "interfaces/Builtins.h"
27 #include "profiles/ProfilesManager.h"
28 #include "settings/lib/Setting.h"
29 #include "threads/SingleLock.h"
30 #include "utils/log.h"
31 #include "utils/RssReader.h"
32 #include "utils/StringUtils.h"
33
34 using namespace std;
35 using namespace XFILE;
36
37 CRssManager::CRssManager()
38 {
39   m_bActive = false;
40 }
41
42 CRssManager::~CRssManager()
43 {
44   Stop();
45 }
46
47 CRssManager& CRssManager::Get()
48 {
49   static CRssManager sRssManager;
50   return sRssManager;
51 }
52
53 void CRssManager::OnSettingsLoaded()
54 {
55   Load();
56 }
57
58 void CRssManager::OnSettingsUnloaded()
59 {
60   Clear();
61 }
62
63 void CRssManager::OnSettingAction(const CSetting *setting)
64 {
65   if (setting == NULL)
66     return;
67
68   const std::string &settingId = setting->GetId();
69   if (settingId == "lookandfeel.rssedit")
70   {
71     ADDON::AddonPtr addon;
72     ADDON::CAddonMgr::Get().GetAddon("script.rss.editor",addon);
73     if (!addon)
74     {
75       if (!CGUIDialogYesNo::ShowAndGetInput(g_localizeStrings.Get(24076), g_localizeStrings.Get(24100), "RSS Editor", g_localizeStrings.Get(24101)))
76         return;
77       CAddonInstaller::Get().Install("script.rss.editor", true, "", false);
78     }
79     CBuiltins::Execute("RunScript(script.rss.editor)");
80   }
81 }
82
83 void CRssManager::Start()
84  {
85    m_bActive = true;
86 }
87
88 void CRssManager::Stop()
89 {
90   CSingleLock lock(m_critical);
91   m_bActive = false;
92   for (unsigned int i = 0; i < m_readers.size(); i++)
93   {
94     if (m_readers[i].reader)
95       delete m_readers[i].reader;
96   }
97   m_readers.clear();
98 }
99
100 bool CRssManager::Load()
101 {
102   CSingleLock lock(m_critical);
103   string rssXML = CProfilesManager::Get().GetUserDataItem("RssFeeds.xml");
104   if (!CFile::Exists(rssXML))
105     return false;
106
107   CXBMCTinyXML rssDoc;
108   if (!rssDoc.LoadFile(rssXML))
109   {
110     CLog::Log(LOGERROR, "CRssManager: error loading %s, Line %d\n%s", rssXML.c_str(), rssDoc.ErrorRow(), rssDoc.ErrorDesc());
111     return false;
112   }
113
114   const TiXmlElement *pRootElement = rssDoc.RootElement();
115   if (pRootElement == NULL || !StringUtils::EqualsNoCase(pRootElement->ValueStr(), "rssfeeds"))
116   {
117     CLog::Log(LOGERROR, "CRssManager: error loading %s, no <rssfeeds> node", rssXML.c_str());
118     return false;
119   }
120
121   m_mapRssUrls.clear();
122   const TiXmlElement* pSet = pRootElement->FirstChildElement("set");
123   while (pSet != NULL)
124   {
125     int iId;
126     if (pSet->QueryIntAttribute("id", &iId) == TIXML_SUCCESS)
127     {
128       RssSet set;
129       set.rtl = pSet->Attribute("rtl") != NULL && strcasecmp(pSet->Attribute("rtl"), "true") == 0;
130       const TiXmlElement* pFeed = pSet->FirstChildElement("feed");
131       while (pFeed != NULL)
132       {
133         int iInterval;
134         if (pFeed->QueryIntAttribute("updateinterval", &iInterval) != TIXML_SUCCESS)
135         {
136           iInterval = 30; // default to 30 min
137           CLog::Log(LOGDEBUG, "CRssManager: no interval set, default to 30!");
138         }
139
140         if (pFeed->FirstChild() != NULL)
141         {
142           // TODO: UTF-8: Do these URLs need to be converted to UTF-8?
143           //              What about the xml encoding?
144           string strUrl = pFeed->FirstChild()->ValueStr();
145           set.url.push_back(strUrl);
146           set.interval.push_back(iInterval);
147         }
148         pFeed = pFeed->NextSiblingElement("feed");
149       }
150
151       m_mapRssUrls.insert(make_pair(iId,set));
152     }
153     else
154       CLog::Log(LOGERROR, "CRssManager: found rss url set with no id in RssFeeds.xml, ignored");
155
156     pSet = pSet->NextSiblingElement("set");
157   }
158
159   return true;
160 }
161
162 bool CRssManager::Reload()
163 {
164   Stop();
165   if (!Load())
166     return false;
167   Start();
168
169   return true;
170 }
171
172 void CRssManager::Clear()
173 {
174   CSingleLock lock(m_critical);
175   m_mapRssUrls.clear();
176 }
177
178 // returns true if the reader doesn't need creating, false otherwise
179 bool CRssManager::GetReader(int controlID, int windowID, IRssObserver* observer, CRssReader *&reader)
180 {
181   CSingleLock lock(m_critical);
182   // check to see if we've already created this reader
183   for (unsigned int i = 0; i < m_readers.size(); i++)
184   {
185     if (m_readers[i].controlID == controlID && m_readers[i].windowID == windowID)
186     {
187       reader = m_readers[i].reader;
188       reader->SetObserver(observer);
189       reader->UpdateObserver();
190       return true;
191     }
192   }
193   // need to create a new one
194   READERCONTROL readerControl;
195   readerControl.controlID = controlID;
196   readerControl.windowID = windowID;
197   reader = readerControl.reader = new CRssReader;
198   m_readers.push_back(readerControl);
199   return false;
200 }