Merge pull request #5070 from Memphiz/osx_fix_devicechanged_recursionbp
[vuplus_xbmc] / xbmc / NfoFile.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 // NfoFile.cpp: implementation of the CNfoFile class.
21 //
22 //////////////////////////////////////////////////////////////////////
23
24 #include "NfoFile.h"
25 #include "video/VideoInfoDownloader.h"
26 #include "addons/AddonManager.h"
27 #include "filesystem/File.h"
28 #include "FileItem.h"
29 #include "music/Album.h"
30 #include "music/Artist.h"
31 #include "settings/Settings.h"
32 #include "utils/log.h"
33
34 #include <vector>
35
36 using namespace std;
37 using namespace XFILE;
38 using namespace ADDON;
39
40 CNfoFile::NFOResult CNfoFile::Create(const CStdString& strPath, const ScraperPtr& info, int episode)
41 {
42   m_info = info; // assume we can use these settings
43   m_type = ScraperTypeFromContent(info->Content());
44   if (FAILED(Load(strPath)))
45     return NO_NFO;
46
47   CFileItemList items;
48   bool bNfo=false;
49
50   AddonPtr addon;
51   ScraperPtr defaultScraper;
52   if (CAddonMgr::Get().GetDefault(m_type, addon))
53     defaultScraper = boost::dynamic_pointer_cast<CScraper>(addon);
54
55   if (m_type == ADDON_SCRAPER_ALBUMS)
56   {
57     CAlbum album;
58     bNfo = GetDetails(album);
59   }
60   else if (m_type == ADDON_SCRAPER_ARTISTS)
61   {
62     CArtist artist;
63     bNfo = GetDetails(artist);
64   }
65   else if (m_type == ADDON_SCRAPER_TVSHOWS || m_type == ADDON_SCRAPER_MOVIES || m_type == ADDON_SCRAPER_MUSICVIDEOS)
66   {
67     // first check if it's an XML file with the info we need
68     CVideoInfoTag details;
69     bNfo = GetDetails(details);
70     if (episode > -1 && bNfo && m_type == ADDON_SCRAPER_TVSHOWS)
71     {
72       int infos=0;
73       m_headofdoc = strstr(m_headofdoc,"<episodedetails");
74       bNfo = GetDetails(details);
75       while (m_headofdoc && details.m_iEpisode != episode)
76       {
77         m_headofdoc = strstr(m_headofdoc+1,"<episodedetails");
78         bNfo  = GetDetails(details);
79         infos++;
80       }
81       if (details.m_iEpisode != episode)
82       {
83         bNfo = false;
84         details.Reset();
85         m_headofdoc = m_doc;
86         if (infos == 1) // still allow differing nfo/file numbers for single ep nfo's
87           bNfo = GetDetails(details);
88       }
89     }
90   }
91
92   vector<ScraperPtr> vecScrapers;
93
94   // add selected scraper - first proirity
95   if (m_info)
96     vecScrapers.push_back(m_info);
97
98   // Add all scrapers except selected and default
99   VECADDONS addons;
100   CAddonMgr::Get().GetAddons(m_type,addons);
101
102   for (unsigned i = 0; i < addons.size(); ++i)
103   {
104     ScraperPtr scraper = boost::dynamic_pointer_cast<CScraper>(addons[i]);
105
106     // skip if scraper requires settings and there's nothing set yet
107     if (scraper->RequiresSettings() && !scraper->HasUserSettings())
108       continue;
109
110     if( (!m_info || m_info->ID() != scraper->ID()) && (!defaultScraper || defaultScraper->ID() != scraper->ID()) )
111       vecScrapers.push_back(scraper);
112   }
113
114   // add default scraper - not user selectable so it's last priority
115   if( defaultScraper && (!m_info || m_info->ID() != defaultScraper->ID()) &&
116       ( !defaultScraper->RequiresSettings() || defaultScraper->HasUserSettings() ) )
117     vecScrapers.push_back(defaultScraper);
118
119   // search ..
120   int res = -1;
121   for (unsigned int i=0;i<vecScrapers.size();++i)
122     if ((res = Scrape(vecScrapers[i])) == 0 || res == 2)
123       break;
124
125   if (res == 2)
126     return ERROR_NFO;
127   if (bNfo)
128     return m_scurl.m_url.empty() ? FULL_NFO : COMBINED_NFO;
129   return m_scurl.m_url.empty() ? NO_NFO : URL_NFO;
130 }
131
132 // return value: 0 - success; 1 - no result; skip; 2 - error
133 int CNfoFile::Scrape(ScraperPtr& scraper)
134 {
135   if (scraper->IsNoop())
136   {
137     m_scurl = CScraperUrl();
138     return 0;
139   }
140   if (scraper->Type() != m_type)
141     return 1;
142   scraper->ClearCache();
143
144   try
145   {
146     m_scurl = scraper->NfoUrl(m_doc);
147   }
148   catch (const CScraperError &sce)
149   {
150     CVideoInfoDownloader::ShowErrorDialog(sce);
151     if (!sce.FAborted())
152       return 2;
153   }
154
155   if (!m_scurl.m_url.empty())
156     SetScraperInfo(scraper);
157   return m_scurl.m_url.empty() ? 1 : 0;
158 }
159
160 int CNfoFile::Load(const CStdString& strFile)
161 {
162   Close();
163   XFILE::CFile file;
164   if (file.Open(strFile))
165   {
166     int size = (int)file.GetLength();
167     try
168     {
169       m_doc = new char[size+1];
170       m_headofdoc = m_doc;
171     }
172     catch (...)
173     {
174       CLog::Log(LOGERROR, "%s: Exception while creating file buffer",__FUNCTION__);
175       return 1;
176     }
177     if (!m_doc)
178     {
179       file.Close();
180       return 1;
181     }
182     file.Read(m_doc, size);
183     m_doc[size] = 0;
184     file.Close();
185     return 0;
186   }
187   return 1;
188 }
189
190 void CNfoFile::Close()
191 {
192   delete[] m_doc;
193   m_doc = NULL;
194   m_scurl.Clear();
195 }