aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornotspiff <spiff@kodi.tv>2017-11-27 16:39:09 +0100
committernotspiff <spiff@kodi.tv>2017-12-20 12:58:40 +0100
commit217b723c5dd41a98e82c1c3786601d0814e37b94 (patch)
treecba109e8864c85982f6125e9878b3583a69f18c4
parentd0e541ac74d2493509a2667e552a8ebe62130f5c (diff)
added: a base video tag loader class
and an associated factory. move nfo handling in VideoInfoScanner behind the new interface. rename PARTIAL_NFO to OVERRIDE_NFO as it is more descriptive. this is a preparatory step for adding support for video info from container tags.
-rw-r--r--cmake/treedata/common/video.txt1
-rw-r--r--xbmc/InfoScanner.h12
-rw-r--r--xbmc/NfoFile.cpp2
-rw-r--r--xbmc/NfoFile.h4
-rw-r--r--xbmc/music/infoscanner/MusicInfoScanner.cpp6
-rw-r--r--xbmc/video/VideoInfoScanner.cpp257
-rw-r--r--xbmc/video/VideoInfoScanner.h12
-rw-r--r--xbmc/video/jobs/VideoLibraryRefreshingJob.cpp19
-rw-r--r--xbmc/video/tags/CMakeLists.txt8
-rw-r--r--xbmc/video/tags/IVideoInfoTagLoader.h67
-rw-r--r--xbmc/video/tags/VideoInfoTagLoaderFactory.cpp42
-rw-r--r--xbmc/video/tags/VideoInfoTagLoaderFactory.h44
-rw-r--r--xbmc/video/tags/VideoTagLoaderNFO.cpp214
-rw-r--r--xbmc/video/tags/VideoTagLoaderNFO.h56
14 files changed, 525 insertions, 219 deletions
diff --git a/cmake/treedata/common/video.txt b/cmake/treedata/common/video.txt
index acfb33bf57..ab534535d3 100644
--- a/cmake/treedata/common/video.txt
+++ b/cmake/treedata/common/video.txt
@@ -1,4 +1,5 @@
xbmc/video video
xbmc/video/dialogs video/dialogs
xbmc/video/jobs video/jobs
+xbmc/video/tags video/tags
xbmc/video/windows video/windows
diff --git a/xbmc/InfoScanner.h b/xbmc/InfoScanner.h
index 2b0f045415..b87a230874 100644
--- a/xbmc/InfoScanner.h
+++ b/xbmc/InfoScanner.h
@@ -47,12 +47,12 @@ public:
enum INFO_TYPE
{
- NO_NFO = 0,
- FULL_NFO = 1,
- URL_NFO = 2,
- COMBINED_NFO = 3,
- ERROR_NFO = 4,
- PARTIAL_NFO = 5
+ NO_NFO = 0, //!< No info found
+ FULL_NFO = 1, //!< Full info specified
+ URL_NFO = 2, //!< A URL to grab info from was found
+ OVERRIDE_NFO = 3, //!< Override info was found
+ COMBINED_NFO = 4, //!< A URL to grab info from + override info was found
+ ERROR_NFO = 5 //!< Error processing info
};
//! \brief Empty destructor.
diff --git a/xbmc/NfoFile.cpp b/xbmc/NfoFile.cpp
index f3571b085c..afa374e4ea 100644
--- a/xbmc/NfoFile.cpp
+++ b/xbmc/NfoFile.cpp
@@ -133,7 +133,7 @@ CInfoScanner::INFO_TYPE CNfoFile::Create(const std::string& strPath,
if (m_scurl.m_url.empty())
{
if (m_doc.find("[scrape url]") != std::string::npos)
- return CInfoScanner::PARTIAL_NFO;
+ return CInfoScanner::OVERRIDE_NFO;
else
return CInfoScanner::FULL_NFO;
}
diff --git a/xbmc/NfoFile.h b/xbmc/NfoFile.h
index f4d6730925..ab7934c05c 100644
--- a/xbmc/NfoFile.h
+++ b/xbmc/NfoFile.h
@@ -54,8 +54,8 @@ public:
}
void Close();
- void SetScraperInfo(const ADDON::ScraperPtr& info) { m_info = info; }
- const ADDON::ScraperPtr& GetScraperInfo() const { return m_info; }
+ void SetScraperInfo(ADDON::ScraperPtr info) { m_info = info; }
+ ADDON::ScraperPtr GetScraperInfo() { return m_info; }
const CScraperUrl &ScraperUrl() const { return m_scurl; }
private:
diff --git a/xbmc/music/infoscanner/MusicInfoScanner.cpp b/xbmc/music/infoscanner/MusicInfoScanner.cpp
index cfb1262114..600d00a7b8 100644
--- a/xbmc/music/infoscanner/MusicInfoScanner.cpp
+++ b/xbmc/music/infoscanner/MusicInfoScanner.cpp
@@ -1355,7 +1355,7 @@ CMusicInfoScanner::DownloadAlbumInfo(const CAlbum& album,
scraper.GetAlbums().clear();
scraper.GetAlbums().push_back(albumNfo);
}
- else if (result != CInfoScanner::PARTIAL_NFO)
+ else if (result != CInfoScanner::OVERRIDE_NFO)
CLog::Log(LOGERROR,"Unable to find an url in nfo file: %s", strNfo.c_str());
}
@@ -1390,7 +1390,7 @@ CMusicInfoScanner::DownloadAlbumInfo(const CAlbum& album,
CGUIDialogSelect *pDlg = NULL;
int iSelectedAlbum=0;
- if ((result == CInfoScanner::NO_NFO || result == CInfoScanner::PARTIAL_NFO)
+ if ((result == CInfoScanner::NO_NFO || result == CInfoScanner::OVERRIDE_NFO)
&& !bMusicBrainz)
{
iSelectedAlbum = -1; // set negative so that we can detect a failure
@@ -1517,7 +1517,7 @@ CMusicInfoScanner::DownloadAlbumInfo(const CAlbum& album,
albumInfo = scraper.GetAlbum(iSelectedAlbum);
- if (result == CInfoScanner::COMBINED_NFO || result == CInfoScanner::PARTIAL_NFO)
+ if (result == CInfoScanner::COMBINED_NFO || result == CInfoScanner::OVERRIDE_NFO)
nfoReader.GetDetails(albumInfo.GetAlbum(), NULL, true);
return INFO_ADDED;
diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp
index 36d56d4e49..b3b8b70482 100644
--- a/xbmc/video/VideoInfoScanner.cpp
+++ b/xbmc/video/VideoInfoScanner.cpp
@@ -57,6 +57,7 @@
#include "video/VideoLibraryQueue.h"
#include "video/VideoThumbLoader.h"
#include "VideoInfoDownloader.h"
+#include "tags/VideoInfoTagLoaderFactory.h"
using namespace XFILE;
using namespace ADDON;
@@ -410,7 +411,6 @@ namespace VIDEO
std::vector<int> seenPaths;
for (int i = 0; i < (int)items.Size(); ++i)
{
- m_nfoReader.Close();
CFileItemPtr pItem = items[i];
// we do this since we may have a override per dir
@@ -529,12 +529,19 @@ namespace VIDEO
CInfoScanner::INFO_TYPE result=CInfoScanner::NO_NFO;
CScraperUrl scrUrl;
// handle .nfo files
+ std::unique_ptr<IVideoInfoTagLoader> loader;
if (useLocal)
- result = CheckForNFOFile(pItem, bDirNames, info2, scrUrl);
+ {
+ loader.reset(CVideoInfoTagLoaderFactory::CreateLoader(*pItem, info2, bDirNames));
+ if (loader)
+ {
+ pItem->GetVideoInfoTag()->Reset();
+ result = loader->Load(*pItem->GetVideoInfoTag(), false);
+ }
+ }
+
if (result == CInfoScanner::FULL_NFO)
{
- pItem->GetVideoInfoTag()->Reset();
- m_nfoReader.GetDetails(*pItem->GetVideoInfoTag());
long lResult = AddVideo(pItem, info2->Content(), bDirNames, useLocal);
if (lResult < 0)
@@ -549,7 +556,10 @@ namespace VIDEO
return INFO_ADDED;
}
if (result == CInfoScanner::URL_NFO || result == CInfoScanner::COMBINED_NFO)
+ {
+ loader->ScraperUrl(scrUrl);
pURL = &scrUrl;
+ }
CScraperUrl url;
int retVal = 0;
@@ -565,8 +575,8 @@ namespace VIDEO
long lResult = -1;
if (GetDetails(pItem, url, info2,
- (result == CInfoScanner::COMBINED_NFO
- || result == CInfoScanner::PARTIAL_NFO) ? &m_nfoReader : NULL,
+ (result == CInfoScanner::COMBINED_NFO ||
+ result == CInfoScanner::OVERRIDE_NFO) ? loader.get() : nullptr,
pDlgProgress))
{
if ((lResult = AddVideo(pItem, info2->Content(), false, useLocal)) < 0)
@@ -605,19 +615,27 @@ namespace VIDEO
CInfoScanner::INFO_TYPE result = CInfoScanner::NO_NFO;
CScraperUrl scrUrl;
// handle .nfo files
+ std::unique_ptr<IVideoInfoTagLoader> loader;
if (useLocal)
- result = CheckForNFOFile(pItem, bDirNames, info2, scrUrl);
+ {
+ loader.reset(CVideoInfoTagLoaderFactory::CreateLoader(*pItem, info2, bDirNames));
+ if (loader)
+ {
+ pItem->GetVideoInfoTag()->Reset();
+ result = loader->Load(*pItem->GetVideoInfoTag(), false);
+ }
+ }
if (result == CInfoScanner::FULL_NFO)
{
- pItem->GetVideoInfoTag()->Reset();
- m_nfoReader.GetDetails(*pItem->GetVideoInfoTag());
-
if (AddVideo(pItem, info2->Content(), bDirNames, true) < 0)
return INFO_ERROR;
return INFO_ADDED;
}
if (result == CInfoScanner::URL_NFO || result == CInfoScanner::COMBINED_NFO)
+ {
+ loader->ScraperUrl(scrUrl);
pURL = &scrUrl;
+ }
CScraperUrl url;
int retVal = 0;
@@ -632,8 +650,8 @@ namespace VIDEO
TranslateContent(info2->Content()).c_str());
if (GetDetails(pItem, url, info2,
- (result == CInfoScanner::COMBINED_NFO
- || result == CInfoScanner::PARTIAL_NFO) ? &m_nfoReader : NULL,
+ (result == CInfoScanner::COMBINED_NFO ||
+ result == CInfoScanner::OVERRIDE_NFO) ? loader.get() : nullptr,
pDlgProgress))
{
if (AddVideo(pItem, info2->Content(), bDirNames, useLocal) < 0)
@@ -667,19 +685,27 @@ namespace VIDEO
CInfoScanner::INFO_TYPE result = CInfoScanner::NO_NFO;
CScraperUrl scrUrl;
// handle .nfo files
+ std::unique_ptr<IVideoInfoTagLoader> loader;
if (useLocal)
- result = CheckForNFOFile(pItem, bDirNames, info2, scrUrl);
+ {
+ loader.reset(CVideoInfoTagLoaderFactory::CreateLoader(*pItem, info2, bDirNames));
+ if (loader)
+ {
+ pItem->GetVideoInfoTag()->Reset();
+ result = loader->Load(*pItem->GetVideoInfoTag(), false);
+ }
+ }
if (result == CInfoScanner::FULL_NFO)
{
- pItem->GetVideoInfoTag()->Reset();
- m_nfoReader.GetDetails(*pItem->GetVideoInfoTag());
-
if (AddVideo(pItem, info2->Content(), bDirNames, true) < 0)
return INFO_ERROR;
return INFO_ADDED;
}
if (result == CInfoScanner::URL_NFO || result == CInfoScanner::COMBINED_NFO)
+ {
+ loader->ScraperUrl(scrUrl);
pURL = &scrUrl;
+ }
CScraperUrl url;
int retVal = 0;
@@ -694,8 +720,8 @@ namespace VIDEO
TranslateContent(info2->Content()).c_str());
if (GetDetails(pItem, url, info2,
- (result == CInfoScanner::COMBINED_NFO
- || result == CInfoScanner::PARTIAL_NFO) ? &m_nfoReader : NULL,
+ (result == CInfoScanner::COMBINED_NFO ||
+ result == CInfoScanner::OVERRIDE_NFO) ? loader.get() : nullptr,
pDlgProgress))
{
if (AddVideo(pItem, info2->Content(), bDirNames, useLocal) < 0)
@@ -1481,7 +1507,6 @@ namespace VIDEO
int iCurr = 1;
for (EPISODELIST::iterator file = files.begin(); file != files.end(); ++file)
{
- m_nfoReader.Close();
if (pDlgProgress)
{
pDlgProgress->SetLine(2, CVariant{20361});
@@ -1509,11 +1534,18 @@ namespace VIDEO
CScraperUrl scrUrl;
ScraperPtr info(scraper);
item.GetVideoInfoTag()->m_iEpisode = file->iEpisode;
+ std::unique_ptr<IVideoInfoTagLoader> loader;
if (useLocal)
- result = CheckForNFOFile(&item, false, info,scrUrl);
+ {
+ loader.reset(CVideoInfoTagLoaderFactory::CreateLoader(item, info, false));
+ if (loader)
+ {
+ // no reset here on purpose
+ result = loader->Load(*item.GetVideoInfoTag(), false);
+ }
+ }
if (result == CInfoScanner::FULL_NFO)
{
- m_nfoReader.GetDetails(*item.GetVideoInfoTag());
// override with episode and season number from file if available
if (file->iEpisode > -1)
{
@@ -1662,117 +1694,10 @@ namespace VIDEO
return INFO_ADDED;
}
- std::string CVideoInfoScanner::GetnfoFile(CFileItem *item, bool bGrabAny) const
- {
- std::string nfoFile;
- // Find a matching .nfo file
- if (!item->m_bIsFolder)
- {
- if (URIUtils::IsInRAR(item->GetPath())) // we have a rarred item - we want to check outside the rars
- {
- CFileItem item2(*item);
- CURL url(item->GetPath());
- std::string strPath = URIUtils::GetDirectory(url.GetHostName());
- item2.SetPath(URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(item->GetPath())));
- return GetnfoFile(&item2, bGrabAny);
- }
-
- // grab the folder path
- std::string strPath = URIUtils::GetDirectory(item->GetPath());
-
- if (bGrabAny && !item->IsStack())
- { // looking up by folder name - movie.nfo takes priority - but not for stacked items (handled below)
- nfoFile = URIUtils::AddFileToFolder(strPath, "movie.nfo");
- if (CFile::Exists(nfoFile))
- return nfoFile;
- }
-
- // try looking for .nfo file for a stacked item
- if (item->IsStack())
- {
- // first try .nfo file matching first file in stack
- CStackDirectory dir;
- std::string firstFile = dir.GetFirstStackedFile(item->GetPath());
- CFileItem item2;
- item2.SetPath(firstFile);
- nfoFile = GetnfoFile(&item2, bGrabAny);
- // else try .nfo file matching stacked title
- if (nfoFile.empty())
- {
- std::string stackedTitlePath = dir.GetStackedTitlePath(item->GetPath());
- item2.SetPath(stackedTitlePath);
- nfoFile = GetnfoFile(&item2, bGrabAny);
- }
- }
- else
- {
- // already an .nfo file?
- if (URIUtils::HasExtension(item->GetPath(), ".nfo"))
- nfoFile = item->GetPath();
- // no, create .nfo file
- else
- nfoFile = URIUtils::ReplaceExtension(item->GetPath(), ".nfo");
- }
-
- // test file existence
- if (!nfoFile.empty() && !CFile::Exists(nfoFile))
- nfoFile.clear();
-
- if (nfoFile.empty()) // final attempt - strip off any cd1 folders
- {
- URIUtils::RemoveSlashAtEnd(strPath); // need no slash for the check that follows
- CFileItem item2;
- if (StringUtils::EndsWithNoCase(strPath, "cd1"))
- {
- strPath.erase(strPath.size() - 3);
- item2.SetPath(URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(item->GetPath())));
- return GetnfoFile(&item2, bGrabAny);
- }
- }
-
- if (nfoFile.empty() && item->IsOpticalMediaFile())
- {
- CFileItem parentDirectory(item->GetLocalMetadataPath(), true);
- nfoFile = GetnfoFile(&parentDirectory, true);
- }
- }
- // folders (or stacked dvds) can take any nfo file if there's a unique one
- if (item->m_bIsFolder || item->IsOpticalMediaFile() || (bGrabAny && nfoFile.empty()))
- {
- // see if there is a unique nfo file in this folder, and if so, use that
- CFileItemList items;
- CDirectory dir;
- std::string strPath;
- if (item->m_bIsFolder)
- strPath = item->GetPath();
- else
- strPath = URIUtils::GetDirectory(item->GetPath());
-
- if (dir.GetDirectory(strPath, items, ".nfo") && items.Size())
- {
- int numNFO = -1;
- for (int i = 0; i < items.Size(); i++)
- {
- if (items[i]->IsNFO())
- {
- if (numNFO == -1)
- numNFO = i;
- else
- {
- numNFO = -1;
- break;
- }
- }
- }
- if (numNFO > -1)
- return items[numNFO]->GetPath();
- }
- }
-
- return nfoFile;
- }
-
- bool CVideoInfoScanner::GetDetails(CFileItem *pItem, CScraperUrl &url, const ScraperPtr& scraper, CNfoFile *nfoFile, CGUIDialogProgress* pDialog /* = NULL */)
+ bool CVideoInfoScanner::GetDetails(CFileItem *pItem, CScraperUrl &url,
+ const ScraperPtr& scraper,
+ IVideoInfoTagLoader* loader,
+ CGUIDialogProgress* pDialog /* = NULL */)
{
CVideoInfoTag movieDetails;
@@ -1784,8 +1709,8 @@ namespace VIDEO
if (ret)
{
- if (nfoFile)
- nfoFile->GetDetails(movieDetails,NULL,true);
+ if (loader)
+ loader->Load(movieDetails, true);
if (m_handle && url.strTitle.empty())
m_handle->SetText(movieDetails.m_strTitle);
@@ -2025,70 +1950,6 @@ namespace VIDEO
}
}
- CInfoScanner::INFO_TYPE CVideoInfoScanner::CheckForNFOFile(CFileItem* pItem, bool bGrabAny, ScraperPtr& info, CScraperUrl& scrUrl)
- {
- std::string strNfoFile;
- if (info->Content() == CONTENT_MOVIES || info->Content() == CONTENT_MUSICVIDEOS
- || (info->Content() == CONTENT_TVSHOWS && !pItem->m_bIsFolder))
- strNfoFile = GetnfoFile(pItem, bGrabAny);
- else if (info->Content() == CONTENT_TVSHOWS && pItem->m_bIsFolder)
- strNfoFile = URIUtils::AddFileToFolder(pItem->GetPath(), "tvshow.nfo");
-
- CInfoScanner::INFO_TYPE result=CInfoScanner::NO_NFO;
- if (!strNfoFile.empty() && CFile::Exists(strNfoFile))
- {
- if (info->Content() == CONTENT_TVSHOWS && !pItem->m_bIsFolder)
- result = m_nfoReader.Create(strNfoFile,info,pItem->GetVideoInfoTag()->m_iEpisode);
- else
- result = m_nfoReader.Create(strNfoFile,info);
-
- std::string type;
- switch(result)
- {
- case CInfoScanner::COMBINED_NFO:
- type = "mixed";
- break;
- case CInfoScanner::FULL_NFO:
- type = "full";
- break;
- case CInfoScanner::URL_NFO:
- type = "URL";
- break;
- case CInfoScanner::NO_NFO:
- type = "";
- break;
- case CInfoScanner::PARTIAL_NFO:
- type = "partial";
- break;
- default:
- type = "malformed";
- }
- if (result != CInfoScanner::NO_NFO)
- CLog::Log(LOGDEBUG, "VideoInfoScanner: Found matching %s NFO file: %s", type.c_str(), CURL::GetRedacted(strNfoFile).c_str());
- if (result == CInfoScanner::FULL_NFO)
- {
- if (info->Content() == CONTENT_TVSHOWS)
- info = m_nfoReader.GetScraperInfo();
- }
- else if (result != CInfoScanner::NO_NFO && result != CInfoScanner::ERROR_NFO)
- {
- if (result != CInfoScanner::PARTIAL_NFO)
- {
- scrUrl = m_nfoReader.ScraperUrl();
- StringUtils::RemoveCRLF(scrUrl.m_url[0].m_url);
- info = m_nfoReader.GetScraperInfo();
- }
-
- if (result != CInfoScanner::URL_NFO)
- m_nfoReader.GetDetails(*pItem->GetVideoInfoTag());
- }
- }
- else
- CLog::Log(LOGDEBUG, "VideoInfoScanner: No NFO file found. Using title search for '%s'", CURL::GetRedacted(pItem->GetPath()).c_str());
-
- return result;
- }
-
bool CVideoInfoScanner::DownloadFailed(CGUIDialogProgress* pDialog)
{
if (g_advancedSettings.m_bVideoScannerIgnoreErrors)
diff --git a/xbmc/video/VideoInfoScanner.h b/xbmc/video/VideoInfoScanner.h
index 50c5713f61..cb912ffe1a 100644
--- a/xbmc/video/VideoInfoScanner.h
+++ b/xbmc/video/VideoInfoScanner.h
@@ -24,7 +24,6 @@
#include <vector>
#include "InfoScanner.h"
-#include "NfoFile.h"
#include "VideoDatabase.h"
#include "addons/Scraper.h"
@@ -34,6 +33,8 @@ class CFileItemList;
namespace VIDEO
{
+ class IVideoInfoTagLoader;
+
typedef struct SScanSettings
{
SScanSettings() { parent_name = parent_name_root = noupdate = exclude = false; recurse = 1;}
@@ -82,7 +83,6 @@ namespace VIDEO
static void ApplyThumbToFolder(const std::string &folder, const std::string &imdbThumb);
static bool DownloadFailed(CGUIDialogProgress* pDlgProgress);
- CInfoScanner::INFO_TYPE CheckForNFOFile(CFileItem* pItem, bool bGrabAny, ADDON::ScraperPtr& scraper, CScraperUrl& scrUrl);
/*! \brief Retrieve any artwork associated with an item
\param pItem item to find artwork for.
@@ -148,7 +148,10 @@ namespace VIDEO
\param pDialog progress dialog to update and check for cancellation during processing. Defaults to NULL.
\return true if information is found, false if an error occurred, the lookup was cancelled, or no information was found.
*/
- bool GetDetails(CFileItem *pItem, CScraperUrl &url, const ADDON::ScraperPtr &scraper, CNfoFile *nfoFile=NULL, CGUIDialogProgress* pDialog=NULL);
+ bool GetDetails(CFileItem *pItem, CScraperUrl &url,
+ const ADDON::ScraperPtr &scraper,
+ VIDEO::IVideoInfoTagLoader* nfoFile = nullptr,
+ CGUIDialogProgress* pDialog = nullptr);
/*! \brief Extract episode and season numbers from a processed regexp
\param reg Regular expression object with at least 2 matches
@@ -224,15 +227,12 @@ namespace VIDEO
bool EnumerateSeriesFolder(CFileItem* item, EPISODELIST& episodeList);
bool ProcessItemByVideoInfoTag(const CFileItem *item, EPISODELIST &episodeList);
- std::string GetnfoFile(CFileItem *item, bool bGrabAny=false) const;
-
bool m_bStop;
bool m_scanAll;
std::string m_strStartDir;
CVideoDatabase m_database;
std::set<std::string> m_pathsToCount;
std::set<int> m_pathsToClean;
- CNfoFile m_nfoReader;
};
}
diff --git a/xbmc/video/jobs/VideoLibraryRefreshingJob.cpp b/xbmc/video/jobs/VideoLibraryRefreshingJob.cpp
index a86c964783..c00146154c 100644
--- a/xbmc/video/jobs/VideoLibraryRefreshingJob.cpp
+++ b/xbmc/video/jobs/VideoLibraryRefreshingJob.cpp
@@ -37,8 +37,11 @@
#include "video/VideoDatabase.h"
#include "video/VideoInfoDownloader.h"
#include "video/VideoInfoScanner.h"
+#include "video/tags/IVideoInfoTagLoader.h"
+#include "video/tags/VideoInfoTagLoaderFactory.h"
using namespace KODI::MESSAGING;
+using namespace VIDEO;
CVideoLibraryRefreshingJob::CVideoLibraryRefreshingJob(CFileItemPtr item, bool forceRefresh, bool refreshAll, bool ignoreNfo /* = false */, const std::string& searchTitle /* = "" */)
: CVideoLibraryProgressJob(nullptr),
@@ -83,7 +86,6 @@ bool CVideoLibraryRefreshingJob::Work(CVideoDatabase &db)
itemTitle = m_item->GetMovieName(scanSettings.parent_name);
CScraperUrl scraperUrl;
- VIDEO::CVideoInfoScanner scanner;
bool needsRefresh = m_forceRefresh;
bool hasDetails = false;
bool ignoreNfo = m_ignoreNfo;
@@ -94,15 +96,25 @@ bool CVideoLibraryRefreshingJob::Work(CVideoDatabase &db)
{
if (!ignoreNfo)
{
+ std::unique_ptr<IVideoInfoTagLoader> loader;
+ loader.reset(CVideoInfoTagLoaderFactory::CreateLoader(*m_item, scraper,
+ scanSettings.parent_name_root));
// check if there's an NFO for the item
- CInfoScanner::INFO_TYPE nfoResult = scanner.CheckForNFOFile(m_item.get(), scanSettings.parent_name_root, scraper, scraperUrl);
+ CInfoScanner::INFO_TYPE nfoResult = CInfoScanner::NO_NFO;
+ if (loader)
+ {
+ CVideoInfoTag dummy;
+ nfoResult = loader->Load(dummy, false);
+ if (nfoResult == CInfoScanner::URL_NFO)
+ loader->ScraperUrl(scraperUrl);
+ }
+
// if there's no NFO remember it in case we have to refresh again
if (nfoResult == CInfoScanner::ERROR_NFO)
ignoreNfo = true;
else if (nfoResult != CInfoScanner::NO_NFO)
hasDetails = true;
-
// if we are performing a forced refresh ask the user to choose between using a valid NFO and a valid scraper
if (needsRefresh && IsModal() && !scraper->IsNoop()
&& nfoResult != CInfoScanner::ERROR_NFO)
@@ -294,6 +306,7 @@ bool CVideoLibraryRefreshingJob::Work(CVideoDatabase &db)
}
// finally download the information for the item
+ CVideoInfoScanner scanner;
if (!scanner.RetrieveVideoInfo(items, scanSettings.parent_name,
scraper->Content(), !ignoreNfo,
scraperUrl.m_url.empty() ? NULL : &scraperUrl,
diff --git a/xbmc/video/tags/CMakeLists.txt b/xbmc/video/tags/CMakeLists.txt
new file mode 100644
index 0000000000..25471fa9fd
--- /dev/null
+++ b/xbmc/video/tags/CMakeLists.txt
@@ -0,0 +1,8 @@
+set(SOURCES VideoInfoTagLoaderFactory.cpp
+ VideoTagLoaderNFO.cpp)
+
+set(HEADERS IVideoInfoTagLoader.h
+ VideoInfoTagLoaderFactory.h
+ VideoTagLoaderNFO.h)
+
+core_add_library(video_tags)
diff --git a/xbmc/video/tags/IVideoInfoTagLoader.h b/xbmc/video/tags/IVideoInfoTagLoader.h
new file mode 100644
index 0000000000..23f082865e
--- /dev/null
+++ b/xbmc/video/tags/IVideoInfoTagLoader.h
@@ -0,0 +1,67 @@
+#pragma once
+/*
+ * Copyright (C) 2017 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "InfoScanner.h"
+#include "addons/Scraper.h"
+#include <string>
+
+class CFileItem;
+class CScraperUrl;
+
+class CVideoInfoTag;
+
+namespace VIDEO
+{
+
+//! \brief Base class for video tag loaders.
+class IVideoInfoTagLoader
+{
+public:
+ //! \brief Constructor
+ //! \param item The item to load info for
+ //! \param info Scraper info
+ //! \param llokInFolder True to look in folder holding file
+ IVideoInfoTagLoader(const CFileItem& item,
+ ADDON::ScraperPtr info,
+ bool lookInFolder) : m_item(item), m_info(info) {}
+ virtual ~IVideoInfoTagLoader() = default;
+
+ //! \brief Returns true if we have info to provide.
+ virtual bool HasInfo() const = 0;
+
+ //! \brief Load tag from file.
+ //! \brief tag Tag to load info into
+ //! \brief prioritise True to prioritise data over existing data in tag
+ //! \returns True if tag was read, false otherwise
+ virtual CInfoScanner::INFO_TYPE Load(CVideoInfoTag& tag, bool prioritise) = 0;
+
+ //! \brief Returns url associated with info (NFO_URL et al).
+ virtual bool ScraperUrl(CScraperUrl&) const { return false; }
+
+ //! \brief Returns current scaper info.
+ const ADDON::ScraperPtr GetAddonInfo() const { return m_info; }
+
+protected:
+ const CFileItem& m_item; //!< Reference to item to load for
+ ADDON::ScraperPtr m_info; //!< Scraper info
+};
+
+}
diff --git a/xbmc/video/tags/VideoInfoTagLoaderFactory.cpp b/xbmc/video/tags/VideoInfoTagLoaderFactory.cpp
new file mode 100644
index 0000000000..9d3cadd8d1
--- /dev/null
+++ b/xbmc/video/tags/VideoInfoTagLoaderFactory.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "VideoInfoTagLoaderFactory.h"
+#include "VideoTagLoaderNFO.h"
+#include "addons/AudioDecoder.h"
+
+using namespace VIDEO;
+
+IVideoInfoTagLoader* CVideoInfoTagLoaderFactory::CreateLoader(const CFileItem& item,
+ ADDON::ScraperPtr info,
+ bool lookInFolder)
+{
+ // don't try to read tags for streams
+ if (item.IsInternetStream())
+ return nullptr;
+
+ CVideoTagLoaderNFO* nfo = new CVideoTagLoaderNFO(item, info, lookInFolder);
+ if (nfo->HasInfo())
+ return nfo;
+
+ delete nfo;
+
+ return nullptr;
+}
diff --git a/xbmc/video/tags/VideoInfoTagLoaderFactory.h b/xbmc/video/tags/VideoInfoTagLoaderFactory.h
new file mode 100644
index 0000000000..84c8407467
--- /dev/null
+++ b/xbmc/video/tags/VideoInfoTagLoaderFactory.h
@@ -0,0 +1,44 @@
+#pragma once
+/*
+ * Copyright (C) 2017 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "IVideoInfoTagLoader.h"
+#include "addons/Scraper.h"
+
+class CFileItem; // forward
+
+namespace VIDEO
+{
+ class CVideoInfoTagLoaderFactory
+ {
+ public:
+ //! \brief Returns a tag loader for the given item.
+ //! \param item The item to find tag loader for
+ //! \param type Type of tag loader. In particular used for tvshows
+ static IVideoInfoTagLoader* CreateLoader(const CFileItem& item,
+ ADDON::ScraperPtr info,
+ bool lookInFolder);
+
+ protected:
+ // No instancing of this class
+ CVideoInfoTagLoaderFactory(void) = delete;
+ virtual ~CVideoInfoTagLoaderFactory() = delete;
+ };
+}
diff --git a/xbmc/video/tags/VideoTagLoaderNFO.cpp b/xbmc/video/tags/VideoTagLoaderNFO.cpp
new file mode 100644
index 0000000000..0a9c9fdaf0
--- /dev/null
+++ b/xbmc/video/tags/VideoTagLoaderNFO.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2005-2017 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Kodi; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "VideoTagLoaderNFO.h"
+#include "FileItem.h"
+#include "filesystem/Directory.h"
+#include "filesystem/File.h"
+#include "filesystem/StackDirectory.h"
+#include "NfoFile.h"
+#include "video/VideoInfoTag.h"
+#include "utils/log.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+
+using namespace XFILE;
+
+CVideoTagLoaderNFO::CVideoTagLoaderNFO(const CFileItem& item,
+ ADDON::ScraperPtr info,
+ bool lookInFolder)
+ : IVideoInfoTagLoader(item, info, lookInFolder)
+{
+ if (m_info->Content() == CONTENT_TVSHOWS && m_item.m_bIsFolder)
+ m_path = URIUtils::AddFileToFolder(m_item.GetPath(), "tvshow.nfo");
+ else
+ m_path = FindNFO(m_item, lookInFolder);
+}
+
+bool CVideoTagLoaderNFO::HasInfo() const
+{
+ return !m_path.empty() && CFile::Exists(m_path);
+}
+
+CInfoScanner::INFO_TYPE CVideoTagLoaderNFO::Load(CVideoInfoTag& tag,
+ bool prioritise)
+{
+ CNfoFile nfoReader;
+ CInfoScanner::INFO_TYPE result;
+ if (m_info->Content() == CONTENT_TVSHOWS && !m_item.m_bIsFolder)
+ result = nfoReader.Create(m_path, m_info, m_item.GetVideoInfoTag()->m_iEpisode);
+ else
+ result = nfoReader.Create(m_path, m_info);
+
+ if (result == CInfoScanner::FULL_NFO || result == CInfoScanner::COMBINED_NFO)
+ nfoReader.GetDetails(tag, nullptr, prioritise);
+
+ if (result == CInfoScanner::URL_NFO || result == CInfoScanner::COMBINED_NFO)
+ m_info = nfoReader.GetScraperInfo();
+
+ std::string type;
+ switch(result)
+ {
+ case CInfoScanner::COMBINED_NFO:
+ type = "mixed";
+ break;
+ case CInfoScanner::FULL_NFO:
+ type = "full";
+ break;
+ case CInfoScanner::URL_NFO:
+ type = "URL";
+ break;
+ case CInfoScanner::NO_NFO:
+ type = "";
+ break;
+ case CInfoScanner::OVERRIDE_NFO:
+ type = "override";
+ break;
+ default:
+ type = "malformed";
+ }
+ if (result != CInfoScanner::NO_NFO)
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: Found matching %s NFO file: %s", type.c_str(), CURL::GetRedacted(m_path).c_str());
+ else
+ CLog::Log(LOGDEBUG, "VideoInfoScanner: No NFO file found. Using title search for '%s'", CURL::GetRedacted(m_item.GetPath()).c_str());
+
+ return result;
+}
+
+bool CVideoTagLoaderNFO::ScraperUrl(CScraperUrl& url) const
+{
+ if (!m_url.m_url.empty())
+ url = m_url;
+
+ return !m_url.m_url.empty();
+}
+
+std::string CVideoTagLoaderNFO::FindNFO(const CFileItem& item,
+ bool movieFolder) const
+{
+ std::string nfoFile;
+ // Find a matching .nfo file
+ if (!item.m_bIsFolder)
+ {
+ if (URIUtils::IsInRAR(item.GetPath())) // we have a rarred item - we want to check outside the rars
+ {
+ CFileItem item2(item);
+ CURL url(m_item.GetPath());
+ std::string strPath = URIUtils::GetDirectory(url.GetHostName());
+ item2.SetPath(URIUtils::AddFileToFolder(strPath,
+ URIUtils::GetFileName(item.GetPath())));
+ return FindNFO(item2, movieFolder);
+ }
+
+ // grab the folder path
+ std::string strPath = URIUtils::GetDirectory(item.GetPath());
+
+ if (movieFolder && !item.IsStack())
+ { // looking up by folder name - movie.nfo takes priority - but not for stacked items (handled below)
+ nfoFile = URIUtils::AddFileToFolder(strPath, "movie.nfo");
+ if (CFile::Exists(nfoFile))
+ return nfoFile;
+ }
+
+ // try looking for .nfo file for a stacked item
+ if (item.IsStack())
+ {
+ // first try .nfo file matching first file in stack
+ CStackDirectory dir;
+ std::string firstFile = dir.GetFirstStackedFile(item.GetPath());
+ CFileItem item2;
+ item2.SetPath(firstFile);
+ nfoFile = FindNFO(item2, movieFolder);
+ // else try .nfo file matching stacked title
+ if (nfoFile.empty())
+ {
+ std::string stackedTitlePath = dir.GetStackedTitlePath(item.GetPath());
+ item2.SetPath(stackedTitlePath);
+ nfoFile = FindNFO(item2, movieFolder);
+ }
+ }
+ else
+ {
+ // already an .nfo file?
+ if (URIUtils::HasExtension(item.GetPath(), ".nfo"))
+ nfoFile = item.GetPath();
+ // no, create .nfo file
+ else
+ nfoFile = URIUtils::ReplaceExtension(item.GetPath(), ".nfo");
+ }
+
+ // test file existence
+ if (!nfoFile.empty() && !CFile::Exists(nfoFile))
+ nfoFile.clear();
+
+ if (nfoFile.empty()) // final attempt - strip off any cd1 folders
+ {
+ URIUtils::RemoveSlashAtEnd(strPath); // need no slash for the check that follows
+ CFileItem item2;
+ if (StringUtils::EndsWithNoCase(strPath, "cd1"))
+ {
+ strPath.erase(strPath.size() - 3);
+ item2.SetPath(URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(item.GetPath())));
+ return FindNFO(item2, movieFolder);
+ }
+ }
+
+ if (nfoFile.empty() && item.IsOpticalMediaFile())
+ {
+ CFileItem parentDirectory(item.GetLocalMetadataPath(), true);
+ nfoFile = FindNFO(parentDirectory, true);
+ }
+ }
+ // folders (or stacked dvds) can take any nfo file if there's a unique one
+ if (item.m_bIsFolder || item.IsOpticalMediaFile() || (movieFolder && nfoFile.empty()))
+ {
+ // see if there is a unique nfo file in this folder, and if so, use that
+ CFileItemList items;
+ CDirectory dir;
+ std::string strPath;
+ if (item.m_bIsFolder)
+ strPath = item.GetPath();
+ else
+ strPath = URIUtils::GetDirectory(item.GetPath());
+
+ if (dir.GetDirectory(strPath, items, ".nfo") && items.Size())
+ {
+ int numNFO = -1;
+ for (int i = 0; i < items.Size(); i++)
+ {
+ if (items[i]->IsNFO())
+ {
+ if (numNFO == -1)
+ numNFO = i;
+ else
+ {
+ numNFO = -1;
+ break;
+ }
+ }
+ }
+ if (numNFO > -1)
+ return items[numNFO]->GetPath();
+ }
+ }
+
+ return nfoFile;
+}
+
diff --git a/xbmc/video/tags/VideoTagLoaderNFO.h b/xbmc/video/tags/VideoTagLoaderNFO.h
new file mode 100644
index 0000000000..0a7112abbf
--- /dev/null
+++ b/xbmc/video/tags/VideoTagLoaderNFO.h
@@ -0,0 +1,56 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2017 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "IVideoInfoTagLoader.h"
+#include "utils/ScraperUrl.h"
+
+#include <string>
+#include <vector>
+
+//! \brief Video tag loader using nfo files.
+class CVideoTagLoaderNFO : public VIDEO::IVideoInfoTagLoader
+{
+public:
+ CVideoTagLoaderNFO(const CFileItem& item,
+ ADDON::ScraperPtr info,
+ bool lookInFolder);
+
+ virtual ~CVideoTagLoaderNFO() = default;
+
+ //! \brief Returns whether or not read has info.
+ bool HasInfo() const override;
+
+ //! \brief Load "tag" from nfo file.
+ //! \brief tag Tag to load info into
+ CInfoScanner::INFO_TYPE Load(CVideoInfoTag& tag, bool prioritise) override;
+
+ //! \brief Returns url associated with info (NFO_URL et al).
+ bool ScraperUrl(CScraperUrl& url) const override;
+
+protected:
+ //! \brief Find nfo file for item
+ //! \param item The item to find NFO file for
+ //! \param movieFolder If true, look for movie.nfo
+ std::string FindNFO(const CFileItem& item, bool movieFolder) const;
+
+ std::string m_path; //!< Path to nfo file
+ CScraperUrl m_url; //!< Resolved url for scraper use
+};