2727using namespace XFILE ;
2828using namespace ADDON ;
2929
30- CInfoScanner::InfoType CNfoFile::Create (const std::string& strPath,
31- const ScraperPtr& info,
32- int index)
30+ // Forward declarations
31+ namespace
3332{
34- m_info = info; // assume we can use these settings
35- m_type = ScraperTypeFromContent (info->Content ());
36- if (Load (strPath) != 0 )
37- return CInfoScanner::InfoType::NONE;
33+ std::vector<ScraperPtr> GetScrapers (AddonType type, const ScraperPtr& selectedScraper);
3834
39- CFileItemList items;
40- bool bNfo=false ;
41- bool overrideNfo{false };
35+ } // unnamed namespace
4236
43- if (m_type == AddonType::SCRAPER_ALBUMS)
37+ CInfoScanner::InfoType CNfoFile::TryParsing (ADDON::AddonType addonType) const
38+ {
39+ using enum CInfoScanner::InfoType;
40+ using enum ADDON::AddonType;
41+
42+ if (addonType == SCRAPER_ALBUMS)
4443 {
4544 CAlbum album;
46- bNfo = GetDetails (album);
45+ return GetDetails (album) ? FULL : NONE ;
4746 }
48- else if (m_type == AddonType:: SCRAPER_ARTISTS)
47+ if (addonType == SCRAPER_ARTISTS)
4948 {
5049 CArtist artist;
51- bNfo = GetDetails (artist);
50+ return GetDetails (artist) ? FULL : NONE ;
5251 }
53- else if (m_type == AddonType::SCRAPER_TVSHOWS || m_type == AddonType::SCRAPER_MOVIES ||
54- m_type == AddonType:: SCRAPER_MUSICVIDEOS)
52+ if (addonType == SCRAPER_MOVIES || addonType == SCRAPER_TVSHOWS ||
53+ addonType == SCRAPER_MUSICVIDEOS)
5554 {
56- CVideoInfoTag details;
57- // Find nth <movie> tag (index is 1 based)
58- // If it doesn't exist then set bNfo to false
59- if (m_type == AddonType::SCRAPER_MOVIES)
60- {
61- m_headPos = m_doc.find (" <movies>" );
62- while (index-- > 0 )
63- {
64- m_headPos = m_doc.find (" <movie" , m_headPos + 1 );
65- if (m_headPos == std::string::npos)
66- break ;
67- }
68- }
69- bNfo = m_headPos != std::string::npos ? GetDetails (details) : false ;
70- overrideNfo = details.GetOverride ();
55+ if (CVideoInfoTag details; GetDetails (details))
56+ return details.GetOverride () ? OVERRIDE : FULL;
7157 }
58+ return NONE;
59+ }
7260
73- std::vector<ScraperPtr> vecScrapers = GetScrapers (m_type, m_info);
74-
75- // search ..
76- int res = -1 ;
77- for (const auto & scraper : vecScrapers)
78- if ((res = Scrape (scraper, m_scurl, m_doc)) == 0 || res == 2 )
61+ bool CNfoFile::SeekToMovieIndex (int index)
62+ {
63+ // Find nth <movie> tag (index is 1 based)
64+ m_headPos = m_doc.find (" <movies>" );
65+ while (index-- > 0 )
66+ {
67+ m_headPos = m_doc.find (" <movie" , m_headPos + 1 );
68+ if (m_headPos == std::string::npos)
7969 break ;
70+ }
71+ return m_headPos != std::string::npos;
72+ }
8073
81- if (res == 2 )
74+ CInfoScanner::InfoType CNfoFile::TryParsing (const CURL& nfoPath,
75+ ADDON::ContentType contentType,
76+ int index /* =1 */ )
77+ {
78+ if (Load (nfoPath) != 0 ) // Setup m_doc and m_headPos
8279 return CInfoScanner::InfoType::ERROR_NFO;
83- if (bNfo)
84- {
85- if (!m_scurl.HasUrls ())
86- {
87- if (overrideNfo || m_doc.find (" [scrape url]" ) != std::string::npos)
88- return CInfoScanner::InfoType::OVERRIDE;
89- else
90- return CInfoScanner::InfoType::FULL;
91- }
92- else
93- return CInfoScanner::InfoType::COMBINED;
94- }
95- return m_scurl.HasUrls () ? CInfoScanner::InfoType::URL : CInfoScanner::InfoType::NONE;
80+
81+ const AddonType addonType = ScraperTypeFromContent (contentType);
82+
83+ if (addonType == ADDON::AddonType::SCRAPER_MOVIES && !SeekToMovieIndex (index))
84+ return CInfoScanner::InfoType::NONE;
85+
86+ return TryParsing (addonType);
87+ }
88+
89+ CInfoScanner::InfoType CNfoFile::Create (const std::string& nfoPath,
90+ const ScraperPtr& info,
91+ int index)
92+ {
93+ /* `TryParsing` creates a close approximation to the desired result.
94+ * The desired result would be knowing if any valid URLs have been
95+ * found in the NFO which could be interpreted by a scraper.
96+ * Determining if any valid URLs exist in the NFO file is an expensive
97+ * operation so should only be called if necessary. If the approximate
98+ * result from `TryParsing` is sufficient then use that result.
99+ *
100+ * Below is a table to show the result from `TryParsing` and the
101+ * potential desired results.
102+ *
103+ * | result | Could be converted to: |
104+ * | -------- | -------------------------- |
105+ * | NONE | URL NONE |
106+ * | OVERRIDE | COMBINED OVERRIDE |
107+ * | FULL | COMBINED OVERRIDE FULL |
108+ *
109+ * The following call to `SearchNfoForScraperUrls` will generate the
110+ * desired result from this approximation.
111+ *
112+ * This call is expensive as it encodes the NFO file into a URL param
113+ * and executes a python interpreter for each installed python scraper.
114+ */
115+ const CInfoScanner::InfoType result = TryParsing (CURL{nfoPath}, info->Content (), index);
116+ if (result == CInfoScanner::InfoType::ERROR_NFO)
117+ return CInfoScanner::InfoType::NONE;
118+ return SearchNfoForScraperUrls (result, info);
96119}
97120
98- // return value: 0 - success; 1 - no result; skip; 2 - error
99- int CNfoFile::Scrape ( const ScraperPtr& scraper, CScraperUrl& url, const std::string& content )
121+ CInfoScanner::InfoType CNfoFile::SearchNfoForScraperUrls (CInfoScanner::InfoType parseResult,
122+ const ScraperPtr& info )
100123{
101- if (scraper->IsNoop ())
102- {
103- url = CScraperUrl ();
104- return 0 ;
105- }
124+ using enum CInfoScanner::InfoType;
106125
107- scraper->ClearCache ();
126+ SetScraperInfo (info); // assume we can use these settings
127+ const AddonType addonType = ScraperTypeFromContent (info->Content ());
108128
109- try
110- {
111- url = scraper->NfoUrl (content);
112- }
113- catch (const CScraperError &sce)
129+ for (const auto & scraper : GetScrapers (addonType, info))
114130 {
115- CVideoInfoDownloader::ShowErrorDialog (sce);
116- if (!sce.FAborted ())
117- return 2 ;
131+ if (scraper->IsNoop ())
132+ {
133+ m_scurl = CScraperUrl ();
134+ break ;
135+ }
136+
137+ scraper->ClearCache ();
138+ try
139+ {
140+ m_scurl = scraper->NfoUrl (m_doc);
141+ }
142+ catch (const CScraperError& sce)
143+ {
144+ CVideoInfoDownloader::ShowErrorDialog (sce);
145+ if (!sce.FAborted ())
146+ return ERROR_NFO;
147+ }
148+
149+ if (m_scurl.HasUrls ())
150+ return (parseResult == FULL || parseResult == OVERRIDE) ? COMBINED : URL;
118151 }
119152
120- return url.HasUrls () ? 0 : 1 ;
153+ if (parseResult == FULL && m_doc.find (" [scrape url]" ) != std::string::npos)
154+ return OVERRIDE;
155+
156+ return parseResult;
121157}
122158
123- int CNfoFile::Load (const std::string& strFile )
159+ int CNfoFile::Load (const CURL& nfoPath )
124160{
125161 Close ();
126162 XFILE::CFile file;
127163 std::vector<uint8_t > buf;
128- if (file.LoadFile (strFile , buf) > 0 )
164+ if (file.LoadFile (nfoPath , buf) > 0 )
129165 {
130166 m_doc.assign (reinterpret_cast <char *>(buf.data ()), buf.size ());
131167 m_headPos = 0 ;
@@ -142,7 +178,10 @@ void CNfoFile::Close()
142178 m_scurl.Clear ();
143179}
144180
145- std::vector<ScraperPtr> CNfoFile::GetScrapers (AddonType type, const ScraperPtr& selectedScraper)
181+ namespace
182+ {
183+
184+ std::vector<ScraperPtr> GetScrapers (AddonType type, const ScraperPtr& selectedScraper)
146185{
147186 AddonPtr addon;
148187 ScraperPtr defaultScraper;
@@ -180,3 +219,5 @@ std::vector<ScraperPtr> CNfoFile::GetScrapers(AddonType type, const ScraperPtr&
180219
181220 return vecScrapers;
182221}
222+
223+ } // unnamed namespace
0 commit comments