diff options
author | Ryan Rector <rmrector@gmail.com> | 2020-08-21 22:39:49 -0600 |
---|---|---|
committer | Ryan Rector <rmrector@gmail.com> | 2020-10-03 15:45:58 -0600 |
commit | 08825f55bbccf272054761c3126d7b407695543b (patch) | |
tree | 59e8161a6de76c275b9a7342e454c906ccec80d8 | |
parent | ddcbadf2c0f631cddd58ea36d926beebc27dc363 (diff) |
add GUI configuration for artwork
-rw-r--r-- | addons/resource.language.en_gb/resources/strings.po | 43 | ||||
-rwxr-xr-x | system/settings/settings.xml | 107 | ||||
-rw-r--r-- | xbmc/FileItem.cpp | 24 | ||||
-rw-r--r-- | xbmc/FileItem.h | 19 | ||||
-rw-r--r-- | xbmc/settings/AdvancedSettings.cpp | 40 | ||||
-rw-r--r-- | xbmc/settings/Settings.cpp | 12 | ||||
-rw-r--r-- | xbmc/settings/Settings.h | 11 | ||||
-rw-r--r-- | xbmc/video/VideoInfoScanner.cpp | 170 | ||||
-rw-r--r-- | xbmc/video/VideoInfoScanner.h | 21 | ||||
-rw-r--r-- | xbmc/video/VideoThumbLoader.cpp | 131 | ||||
-rw-r--r-- | xbmc/video/VideoThumbLoader.h | 4 |
11 files changed, 439 insertions, 143 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index df337cf8f6..f005cf1302 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -22247,4 +22247,47 @@ msgstr "" #: system/settings/settings.xml msgctxt "#39142" msgid "Custom" + +#: system/settings/settings.xml +msgctxt "#39143" +msgid "Movie art types whitelist" +msgstr "" + +#. Description of setting with label #39150 "Movie art types whitelist" +#: system/settings/settings.xml +msgctxt "#39144" +msgid "Limit the movie and movie set artwork fetched locally or applied from scraper remote art results to just those art types in the whitelist" +msgstr "" + +#: system/settings/settings.xml +msgctxt "#39145" +msgid "TV show art types whitelist" +msgstr "" + +#. Description of setting with label #39152 "TV show art types whitelist" +#: system/settings/settings.xml +msgctxt "#39146" +msgid "Limit the TV show and season artwork fetched locally or applied from scraper remote art results to just those art types in the whitelist" +msgstr "" + +#: system/settings/settings.xml +msgctxt "#39147" +msgid "Episode art types whitelist" +msgstr "" + +#. Description of setting with label #39154 "Episode art types whitelist" +#: system/settings/settings.xml +msgctxt "#39148" +msgid "Limit the episode artwork fetched locally or applied from scraper remote art results to just those art types in the whitelist" +msgstr "" + +#: system/settings/settings.xml +msgctxt "#39149" +msgid "Music video art types whitelist" +msgstr "" + +#. Description of setting with label #39156 "Music video art types whitelist" +#: system/settings/settings.xml +msgctxt "#39150" +msgid "Limit the music video artwork fetched locally or applied from scraper remote art results to just those art types in the whitelist" msgstr "" diff --git a/system/settings/settings.xml b/system/settings/settings.xml index e6c10e26e0..893a64e2b4 100755 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml @@ -1000,6 +1000,113 @@ </control> </setting> </group> + <group id="4" label="39123"> + <!-- Hidden setting indicating video art settings have been migrated from old advancedsettings.xml format--> + <setting id="videolibrary.artsettingsupdated" type="boolean" label="0" help=""> + <level>4</level> + <default>false</default> + <control type="toggle" /> + </setting> + <setting id="videolibrary.artworklevel" type="integer" label="39137" help="39138"> + <level>1</level> + <default>0</default> + <constraints> + <options> + <option label="39140">0</option> <!-- VIDEOLIBRARY_ARTWORK_LEVEL_ALL --> + <option label="39141">1</option> <!-- VIDEOLIBRARY_ARTWORK_LEVEL_BASIC --> + <option label="39142">2</option> <!-- VIDEOLIBRARY_ARTWORK_LEVEL_CUSTOM --> + <option label="231">3</option> <!-- VIDEOLIBRARY_ARTWORK_LEVEL_NONE --> + </options> + </constraints> + <control type="list" format="string" /> + </setting> + <setting id="videolibrary.movieartwhitelist" type="list[string]" parent="videolibrary.artworklevel" label="39143" help="39144"> + <level>2</level> + <default></default> + <constraints> + <options> + <option>clearart</option> + <option>discart</option> + <option>keyart</option> + <option>banner</option> + <option>landscape</option> + <option>clearlogo</option> + </options> + <delimiter>, </delimiter> + <allownewoption>true</allownewoption> + </constraints> + <dependencies> + <dependency type="visible" setting="videolibrary.artworklevel" operator="is">2</dependency> + </dependencies> + <control type="list" format="string"> + <multiselect>true</multiselect> + <addbuttonlabel>13516</addbuttonlabel> + </control> + </setting> + <setting id="videolibrary.tvshowartwhitelist" type="list[string]" parent="videolibrary.artworklevel" label="39145" help="39146"> + <level>2</level> + <default></default> + <constraints> + <options> + <option>clearart</option> + <option>discart</option> + <option>keyart</option> + <option>banner</option> + <option>landscape</option> + <option>clearlogo</option> + </options> + <delimiter>, </delimiter> + <allownewoption>true</allownewoption> + </constraints> + <dependencies> + <dependency type="visible" setting="videolibrary.artworklevel" operator="is">2</dependency> + </dependencies> + <control type="list" format="string"> + <multiselect>true</multiselect> + <addbuttonlabel>13516</addbuttonlabel> + </control> + </setting> + <setting id="videolibrary.episodeartwhitelist" type="list[string]" parent="videolibrary.artworklevel" label="39147" help="39148"> + <level>2</level> + <default></default> + <constraints> + <options> + <option>fanart</option> + </options> + <delimiter>, </delimiter> + <allownewoption>true</allownewoption> + </constraints> + <dependencies> + <dependency type="visible" setting="videolibrary.artworklevel" operator="is">2</dependency> + </dependencies> + <control type="list" format="string"> + <multiselect>true</multiselect> + <addbuttonlabel>13516</addbuttonlabel> + </control> + </setting> + <setting id="videolibrary.musicvideoartwhitelist" type="list[string]" parent="videolibrary.artworklevel" label="39149" help="39150"> + <level>2</level> + <default></default> + <constraints> + <options> + <option>clearart</option> + <option>discart</option> + <option>banner</option> + <option>landscape</option> + <option>clearlogo</option> + </options> + <delimiter>, </delimiter> + <allownewoption>true</allownewoption> + </constraints> + <dependencies> + <dependency type="visible" setting="videolibrary.artworklevel" operator="is">2</dependency> + </dependencies> + <control type="list" format="string"> + <multiselect>true</multiselect> + <addbuttonlabel>13516</addbuttonlabel> + </control> + </setting> + </group> </category> <category id="music" label="14216" help="38108"> <group id="1" label="39121"> diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp index c2f054992d..a268b256f6 100644 --- a/xbmc/FileItem.cpp +++ b/xbmc/FileItem.cpp @@ -3220,19 +3220,17 @@ std::string CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) return ""; } -std::string CFileItem::GetLocalArt(const std::string &artFile, bool useFolder) const +std::string CFileItem::GetLocalArtBaseFilename() const { - // no retrieving of empty art files from folders - if (useFolder && artFile.empty()) - return ""; + bool useFolder = false; + return GetLocalArtBaseFilename(useFolder); +} +std::string CFileItem::GetLocalArtBaseFilename(bool& useFolder) const +{ std::string strFile = m_strPath; if (IsStack()) { -/* CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false); - std::string localArt = item.GetLocalArt(artFile); - return localArt; - */ std::string strPath; URIUtils::GetParentPath(m_strPath,strPath); strFile = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile))); @@ -3257,6 +3255,16 @@ std::string CFileItem::GetLocalArt(const std::string &artFile, bool useFolder) c else if (useFolder && !(m_bIsFolder && !IsFileFolder())) strFile = URIUtils::GetDirectory(strFile); + return strFile; +} + +std::string CFileItem::GetLocalArt(const std::string& artFile, bool useFolder) const +{ + // no retrieving of empty art files from folders + if (useFolder && artFile.empty()) + return ""; + + std::string strFile = GetLocalArtBaseFilename(useFolder); if (strFile.empty()) // empty filepath -> nothing to find return ""; diff --git a/xbmc/FileItem.h b/xbmc/FileItem.h index 347009d7d1..305db92632 100644 --- a/xbmc/FileItem.h +++ b/xbmc/FileItem.h @@ -385,6 +385,23 @@ public: */ std::string GetLocalFanart() const; + /*! + \brief Assemble the base filename of local artwork for an item, + accounting for archives, stacks and multi-paths, and BDMV/VIDEO_TS folders. + `useFolder` is set to false + \return the path to the base filename for artwork lookup. + \sa GetLocalArt + */ + std::string GetLocalArtBaseFilename() const; + /*! + \brief Assemble the base filename of local artwork for an item, + accounting for archives, stacks and multi-paths, and BDMV/VIDEO_TS folders. + \param useFolder whether to look in the folder for the art file. Defaults to false. + \return the path to the base filename for artwork lookup. + \sa GetLocalArt + */ + std::string GetLocalArtBaseFilename(bool& useFolder) const; + /*! \brief Assemble the filename of a particular piece of local artwork for an item. No file existence check is typically performed. \param artFile the art file to search for. @@ -392,7 +409,7 @@ public: \return the path to the local artwork. \sa FindLocalArt */ - std::string GetLocalArt(const std::string &artFile, bool useFolder = false) const; + std::string GetLocalArt(const std::string& artFile, bool useFolder = false) const; /*! \brief Assemble the filename of a particular piece of local artwork for an item, and check for file existence. diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp index 910b5e1ffe..e4a2d57ea9 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp @@ -1440,4 +1440,44 @@ void CAdvancedSettings::MigrateOldArtSettings() // Flag migration of settings so not done again settings->SetBool(CSettings::SETTING_MUSICLIBRARY_ARTSETTINGS_UPDATED, true); } + + if (!settings->GetBool(CSettings::SETTING_VIDEOLIBRARY_ARTSETTINGS_UPDATED)) + { + CLog::Log(LOGINFO, "Migrating old video library artwork settings to new GUI settings"); + // Convert numeric art type variants into simple art type family entry + // e.g. {"banner", "fanart1", "fanart2", "fanart3"... } into { "banner", "fanart"} + if (!m_videoEpisodeExtraArt.empty()) + { + std::vector<CVariant> whitelist; + ConvertToWhitelist(m_videoEpisodeExtraArt, whitelist); + settings->SetList(CSettings::SETTING_VIDEOLIBRARY_EPISODEART_WHITELIST, whitelist); + } + if (!m_videoTvShowExtraArt.empty()) + { + std::vector<CVariant> whitelist; + ConvertToWhitelist(m_videoTvShowExtraArt, whitelist); + settings->SetList(CSettings::SETTING_VIDEOLIBRARY_TVSHOWART_WHITELIST, whitelist); + } + if (!m_videoMovieExtraArt.empty()) + { + std::vector<CVariant> whitelist; + ConvertToWhitelist(m_videoMovieExtraArt, whitelist); + settings->SetList(CSettings::SETTING_VIDEOLIBRARY_MOVIEART_WHITELIST, whitelist); + } + if (!m_videoMusicVideoExtraArt.empty()) + { + std::vector<CVariant> whitelist; + ConvertToWhitelist(m_videoMusicVideoExtraArt, whitelist); + settings->SetList(CSettings::SETTING_VIDEOLIBRARY_MUSICVIDEOART_WHITELIST, whitelist); + } + + // Whitelists configured, set artwork level to custom + if (!m_videoEpisodeExtraArt.empty() || !m_videoTvShowExtraArt.empty() + || !m_videoMovieExtraArt.empty() || !m_videoMusicVideoExtraArt.empty()) + settings->SetInt(CSettings::SETTING_VIDEOLIBRARY_ARTWORK_LEVEL, + CSettings::MUSICLIBRARY_ARTWORK_LEVEL_CUSTOM); + + // Flag migration of settings so not done again + settings->SetBool(CSettings::SETTING_VIDEOLIBRARY_ARTSETTINGS_UPDATED, true); + } } diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp index f187e13653..b71c4ba8b9 100644 --- a/xbmc/settings/Settings.cpp +++ b/xbmc/settings/Settings.cpp @@ -115,6 +115,18 @@ const std::string CSettings::SETTING_VIDEOLIBRARY_EXPORT = "videolibrary.export" const std::string CSettings::SETTING_VIDEOLIBRARY_IMPORT = "videolibrary.import"; const std::string CSettings::SETTING_VIDEOLIBRARY_SHOWEMPTYTVSHOWS = "videolibrary.showemptytvshows"; const std::string CSettings::SETTING_VIDEOLIBRARY_MOVIESETSFOLDER = "videolibrary.moviesetsfolder"; +const std::string CSettings::SETTING_VIDEOLIBRARY_ARTWORK_LEVEL = + "videolibrary.artworklevel"; +const std::string CSettings::SETTING_VIDEOLIBRARY_MOVIEART_WHITELIST = + "videolibrary.movieartwhitelist"; +const std::string CSettings::SETTING_VIDEOLIBRARY_TVSHOWART_WHITELIST = + "videolibrary.tvshowartwhitelist"; +const std::string CSettings::SETTING_VIDEOLIBRARY_EPISODEART_WHITELIST = + "videolibrary.episodeartwhitelist"; +const std::string CSettings::SETTING_VIDEOLIBRARY_MUSICVIDEOART_WHITELIST = + "videolibrary.musicvideoartwhitelist"; +const std::string CSettings::SETTING_VIDEOLIBRARY_ARTSETTINGS_UPDATED = + "videolibrary.artsettingsupdated"; const std::string CSettings::SETTING_LOCALE_AUDIOLANGUAGE = "locale.audiolanguage"; const std::string CSettings::SETTING_VIDEOPLAYER_PREFERDEFAULTFLAG = "videoplayer.preferdefaultflag"; const std::string CSettings::SETTING_VIDEOPLAYER_AUTOPLAYNEXTITEM = "videoplayer.autoplaynextitem"; diff --git a/xbmc/settings/Settings.h b/xbmc/settings/Settings.h index c01ba3e7a1..3d6d6e1aba 100644 --- a/xbmc/settings/Settings.h +++ b/xbmc/settings/Settings.h @@ -83,6 +83,12 @@ public: static const std::string SETTING_VIDEOLIBRARY_IMPORT; static const std::string SETTING_VIDEOLIBRARY_SHOWEMPTYTVSHOWS; static const std::string SETTING_VIDEOLIBRARY_MOVIESETSFOLDER; + static const std::string SETTING_VIDEOLIBRARY_ARTWORK_LEVEL; + static const std::string SETTING_VIDEOLIBRARY_MOVIEART_WHITELIST; + static const std::string SETTING_VIDEOLIBRARY_TVSHOWART_WHITELIST; + static const std::string SETTING_VIDEOLIBRARY_EPISODEART_WHITELIST; + static const std::string SETTING_VIDEOLIBRARY_MUSICVIDEOART_WHITELIST; + static const std::string SETTING_VIDEOLIBRARY_ARTSETTINGS_UPDATED; static const std::string SETTING_LOCALE_AUDIOLANGUAGE; static const std::string SETTING_VIDEOPLAYER_PREFERDEFAULTFLAG; static const std::string SETTING_VIDEOPLAYER_AUTOPLAYNEXTITEM; @@ -395,6 +401,11 @@ public: static const int VIDEOLIBRARY_PLOTS_SHOW_UNWATCHED_MOVIES = 0; static const int VIDEOLIBRARY_PLOTS_SHOW_UNWATCHED_TVSHOWEPISODES = 1; static const int VIDEOLIBRARY_THUMB_SHOW_UNWATCHED_EPISODE = 2; + // values for SETTING_VIDEOLIBRARY_ARTWORK_LEVEL + static const int VIDEOLIBRARY_ARTWORK_LEVEL_ALL = 0; + static const int VIDEOLIBRARY_ARTWORK_LEVEL_BASIC = 1; + static const int VIDEOLIBRARY_ARTWORK_LEVEL_CUSTOM = 2; + static const int VIDEOLIBRARY_ARTWORK_LEVEL_NONE = 3; // values for SETTING_MUSICLIBRARY_ARTWORKLEVEL static const int MUSICLIBRARY_ARTWORK_LEVEL_ALL = 0; diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp index 6d1f7dbed5..8ee1f830ce 100644 --- a/xbmc/video/VideoInfoScanner.cpp +++ b/xbmc/video/VideoInfoScanner.cpp @@ -1445,6 +1445,7 @@ namespace VIDEO if (path.empty()) return ""; path = URIUtils::AddFileToFolder(path, CUtil::MakeLegalFileName(setTitle, LEGAL_WIN32_COMPAT)); + URIUtils::AddSlashAtEnd(path); CLog::Log(LOGDEBUG, "VideoInfoScanner: Looking for local artwork for movie set '{}' in folder '{}'", setTitle, @@ -1452,10 +1453,11 @@ namespace VIDEO return CDirectory::Exists(path) ? path : ""; } - void CVideoInfoScanner::GetLocalMovieSetArtwork(CGUIListItem::ArtMap& art, - const std::vector<std::string>& artTypes, const std::string& setTitle) + void CVideoInfoScanner::AddLocalItemArtwork(CGUIListItem::ArtMap& itemArt, + const std::vector<std::string>& wantedArtTypes, const std::string& itemPath, + bool addAll, bool exactName) { - std::string path = GetMovieSetInfoFolder(setTitle); + std::string path = URIUtils::GetDirectory(itemPath); if (path.empty()) return; @@ -1464,21 +1466,47 @@ namespace VIDEO CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); + std::string baseFilename = URIUtils::GetFileName(itemPath); + if (!baseFilename.empty()) + { + URIUtils::RemoveExtension(baseFilename); + baseFilename.append("-"); + } + for (const auto& artFile : availableArtFiles) { std::string candidate = URIUtils::GetFileName(artFile->GetPath()); + + bool matchesFilename = + !baseFilename.empty() && StringUtils::StartsWith(candidate, baseFilename); + if (!baseFilename.empty() && !matchesFilename) + continue; + + if (matchesFilename) + candidate.erase(0, baseFilename.length()); URIUtils::RemoveExtension(candidate); - for (const auto& artType : artTypes) + StringUtils::ToLower(candidate); + + // move 'folder' to thumb / poster / banner based on aspect ratio + // if such artwork doesn't already exist + if (!matchesFilename && StringUtils::EqualsNoCase(candidate, "folder") && + !CVideoThumbLoader::IsArtTypeInWhitelist("folder", wantedArtTypes, exactName)) { - if (!StringUtils::StartsWith(artType, "set.")) - continue; - std::string realType = artType.substr(4); - if (StringUtils::EqualsNoCase(candidate, realType)) + // cache the image to determine sizing + CTextureDetails details; + if (CTextureCache::GetInstance().CacheImage(artFile->GetPath(), details)) { - art[artType] = artFile->GetPath(); - break; + candidate = GetArtTypeFromSize(details.width, details.height); + if (itemArt.find(candidate) != itemArt.end()) + continue; } } + + if ((addAll && CVideoThumbLoader::IsValidArtType(candidate)) || + CVideoThumbLoader::IsArtTypeInWhitelist(candidate, wantedArtTypes, exactName)) + { + itemArt[candidate] = artFile->GetPath(); + } } } @@ -1491,41 +1519,45 @@ namespace VIDEO CGUIListItem::ArtMap art = pItem->GetArt(); // get and cache thumb images - std::vector<std::string> artTypes = CVideoThumbLoader::GetArtTypes(ContentToMediaType(content, pItem->m_bIsFolder)); - bool lookForThumb = find(artTypes.begin(), artTypes.end(), "thumb") == artTypes.end() && - art.find("thumb") == art.end(); + std::string mediaType = ContentToMediaType(content, pItem->m_bIsFolder); + std::vector<std::string> artTypes = CVideoThumbLoader::GetArtTypes(mediaType); bool moviePartOfSet = content == CONTENT_MOVIES && !movieDetails.m_set.title.empty(); + std::vector<std::string> movieSetArtTypes; if (moviePartOfSet) { - for (std::string artType : CVideoThumbLoader::GetArtTypes(MediaTypeVideoCollection)) + movieSetArtTypes = CVideoThumbLoader::GetArtTypes(MediaTypeVideoCollection); + for (std::string artType : movieSetArtTypes) artTypes.push_back("set." + artType); } + int artLevel = CServiceBroker::GetSettingsComponent()->GetSettings()-> + GetInt(CSettings::SETTING_VIDEOLIBRARY_ARTWORK_LEVEL); + bool addAll = artLevel == CSettings::VIDEOLIBRARY_ARTWORK_LEVEL_ALL; + bool exactName = artLevel == CSettings::VIDEOLIBRARY_ARTWORK_LEVEL_BASIC; // find local art if (useLocal) { - for (std::vector<std::string>::const_iterator i = artTypes.begin(); i != artTypes.end(); ++i) + if (!pItem->SkipLocalArt()) { - if (art.find(*i) == art.end()) + if (bApplyToDir && (content == CONTENT_MOVIES || content == CONTENT_MUSICVIDEOS)) { - std::string image = CVideoThumbLoader::GetLocalArt(*pItem, *i, bApplyToDir); - if (!image.empty()) - art.insert(std::make_pair(*i, image)); + std::string filename = pItem->GetLocalArtBaseFilename(); + std::string directory = URIUtils::GetDirectory(filename); + if (filename != directory) + AddLocalItemArtwork(art, artTypes, directory, addAll, exactName); } + AddLocalItemArtwork(art, artTypes, pItem->GetLocalArtBaseFilename(), addAll, exactName); } + if (moviePartOfSet) - GetLocalMovieSetArtwork(art, artTypes, movieDetails.m_set.title); - // find and classify the local thumb (backcompat) if available - if (lookForThumb) { - std::string image = CVideoThumbLoader::GetLocalArt(*pItem, "thumb", bApplyToDir); - if (!image.empty()) - { // cache the image and determine sizing - CTextureDetails details; - if (CTextureCache::GetInstance().CacheImage(image, details)) + std::string movieSetInfoPath = GetMovieSetInfoFolder(movieDetails.m_set.title); + if (!movieSetInfoPath.empty()) + { + CGUIListItem::ArtMap movieSetArt; + AddLocalItemArtwork(movieSetArt, movieSetArtTypes, movieSetInfoPath, addAll, exactName); + for (const auto& artItem : movieSetArt) { - std::string type = GetArtTypeFromSize(details.width, details.height); - if (art.find(type) == art.end()) - art.insert(std::make_pair(type, image)); + art["set." + artItem.first] = artItem.second; } } } @@ -1536,7 +1568,8 @@ namespace VIDEO { for (auto& it : pItem->GetVideoInfoTag()->m_coverArt) { - if (std::find(artTypes.begin(), artTypes.end(), it.m_type) != artTypes.end() && art.find(it.m_type) == art.end()) + if ((addAll || CVideoThumbLoader::IsArtTypeInWhitelist(it.m_type, artTypes, exactName)) && + art.find(it.m_type) == art.end()) { std::string thumb = CTextureUtils::GetWrappedImageURL(pItem->GetPath(), "video_" + it.m_type); @@ -1546,7 +1579,8 @@ namespace VIDEO } // add online fanart (treated separately due to it being stored in m_fanart) - if (find(artTypes.begin(), artTypes.end(), "fanart") != artTypes.end() && art.find("fanart") == art.end()) + if ((addAll || CVideoThumbLoader::IsArtTypeInWhitelist("fanart", artTypes, exactName)) && + art.find("fanart") == art.end()) { std::string fanart = pItem->GetVideoInfoTag()->m_fanart.GetImageURL(); if (!fanart.empty()) @@ -1561,16 +1595,22 @@ namespace VIDEO std::string aspect = url.m_aspect; if (aspect.empty()) // Backward compatibility with Kodi 11 Eden NFO files - aspect = ContentToMediaType(content, pItem->m_bIsFolder) == MediaTypeEpisode ? "thumb" : "poster"; - if (find(artTypes.begin(), artTypes.end(), aspect) == artTypes.end() || art.find(aspect) != art.end()) - continue; - std::string image = GetImage(url, pItem->GetPath()); - if (!image.empty()) - art.insert(std::make_pair(aspect, image)); + aspect = mediaType == MediaTypeEpisode ? "thumb" : "poster"; + + if ((addAll || CVideoThumbLoader::IsArtTypeInWhitelist(aspect, artTypes, exactName)) && + art.find(aspect) == art.end()) + { + std::string image = GetImage(url, pItem->GetPath()); + if (!image.empty()) + art.insert(std::make_pair(aspect, image)); + } } - for (CGUIListItem::ArtMap::const_iterator i = art.begin(); i != art.end(); ++i) - CTextureCache::GetInstance().BackgroundCacheImage(i->second); + for (const auto& artType : artTypes) + { + if (art.find(artType) != art.end()) + CTextureCache::GetInstance().BackgroundCacheImage(art[artType]); + } pItem->SetArt(art); @@ -1965,16 +2005,21 @@ namespace VIDEO void CVideoInfoScanner::GetSeasonThumbs(const CVideoInfoTag &show, std::map<int, std::map<std::string, std::string>> &seasonArt, const std::vector<std::string> &artTypes, bool useLocal) { + int artLevel = CServiceBroker::GetSettingsComponent()->GetSettings()-> + GetInt(CSettings::SETTING_VIDEOLIBRARY_ARTWORK_LEVEL); + bool addAll = artLevel == CSettings::VIDEOLIBRARY_ARTWORK_LEVEL_ALL; + bool exactName = artLevel == CSettings::VIDEOLIBRARY_ARTWORK_LEVEL_BASIC; if (useLocal) { - bool lookForThumb = find(artTypes.begin(), artTypes.end(), "thumb") == artTypes.end(); - // find the maximum number of seasons we have local thumbs for int maxSeasons = 0; CFileItemList items; - CDirectory::GetDirectory(show.m_strPath, items, ".png|.jpg|.tbn", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_NO_FILE_INFO); + std::string extensions = CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(); + CDirectory::GetDirectory(show.m_strPath, items, extensions, + DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); + extensions.erase(std::remove(extensions.begin(), extensions.end(), '.'), extensions.end()); CRegExp reg; - if (items.Size() && reg.RegComp("season([0-9]+)(-[a-z]+)?\\.(tbn|jpg|png)")) + if (items.Size() && reg.RegComp("season([0-9]+)(-[a-z0-9]+)?\\.(" + extensions + ")")) { for (const auto& item : items) { @@ -2002,29 +2047,10 @@ namespace VIDEO basePath = "season-specials"; else basePath = StringUtils::Format("season%02i", season); - CFileItem artItem(URIUtils::AddFileToFolder(show.m_strPath, basePath), false); - for (std::vector<std::string>::const_iterator i = artTypes.begin(); i != artTypes.end(); ++i) - { - std::string image = CVideoThumbLoader::GetLocalArt(artItem, *i, false); - if (!image.empty()) - art.insert(std::make_pair(*i, image)); - } - // find and classify the local thumb (backcompat) if available - if (lookForThumb) - { - std::string image = CVideoThumbLoader::GetLocalArt(artItem, "thumb", false); - if (!image.empty()) - { // cache the image and determine sizing - CTextureDetails details; - if (CTextureCache::GetInstance().CacheImage(image, details)) - { - std::string type = GetArtTypeFromSize(details.width, details.height); - if (art.find(type) == art.end()) - art.insert(std::make_pair(type, image)); - } - } - } + AddLocalItemArtwork(art, artTypes, + URIUtils::AddFileToFolder(show.m_strPath, basePath), + addAll, exactName); seasonArt[season] = art; } @@ -2038,11 +2064,13 @@ namespace VIDEO if (aspect.empty()) aspect = "thumb"; std::map<std::string, std::string>& art = seasonArt[url.m_season]; - if (find(artTypes.begin(), artTypes.end(), aspect) == artTypes.end() || art.find(aspect) != art.end()) - continue; - std::string image = CScraperUrl::GetThumbUrl(url); - if (!image.empty()) - art.insert(std::make_pair(aspect, image)); + if ((addAll || CVideoThumbLoader::IsArtTypeInWhitelist(aspect, artTypes, exactName)) && + art.find(aspect) == art.end()) + { + std::string image = CScraperUrl::GetThumbUrl(url); + if (!image.empty()) + art.insert(std::make_pair(aspect, image)); + } } } diff --git a/xbmc/video/VideoInfoScanner.h b/xbmc/video/VideoInfoScanner.h index 7c221aaf3d..f50c228d1b 100644 --- a/xbmc/video/VideoInfoScanner.h +++ b/xbmc/video/VideoInfoScanner.h @@ -91,14 +91,6 @@ namespace VIDEO */ void GetArtwork(CFileItem *pItem, const CONTENT_TYPE &content, bool bApplyToDir=false, bool useLocal=true, const std::string &actorArtPath = ""); - /*! \brief Retrieve the art type for an image from the given size. - \param width the width of the image. - \param height the height of the image. - \return "poster" if the aspect ratio is at most 4:5, "banner" if the aspect ratio - is at least 1:4, "thumb" otherwise. - */ - static std::string GetArtTypeFromSize(unsigned int width, unsigned int height); - /*! \brief Get season thumbs for a tvshow. All seasons (regardless of whether the user has episodes) are added to the art map. \param show tvshow info tag @@ -244,8 +236,17 @@ namespace VIDEO std::set<int> m_pathsToClean; private: - void GetLocalMovieSetArtwork(CGUIListItem::ArtMap& art, - const std::vector<std::string>& artTypes, const std::string& setTitle); + static void AddLocalItemArtwork(CGUIListItem::ArtMap& itemArt, + const std::vector<std::string>& wantedArtTypes, const std::string& itemPath, + bool addAll, bool exactName); + + /*! \brief Retrieve the art type for an image from the given size. + \param width the width of the image. + \param height the height of the image. + \return "poster" if the aspect ratio is at most 4:5, "banner" if the aspect ratio + is at least 1:4, "thumb" otherwise. + */ + static std::string GetArtTypeFromSize(unsigned int width, unsigned int height); }; } diff --git a/xbmc/video/VideoThumbLoader.cpp b/xbmc/video/VideoThumbLoader.cpp index 4610233ecc..b2fee57676 100644 --- a/xbmc/video/VideoThumbLoader.cpp +++ b/xbmc/video/VideoThumbLoader.cpp @@ -223,68 +223,93 @@ static void SetupRarOptions(CFileItem& item, const std::string& path) g_directoryCache.ClearDirectory(url.GetWithoutFilename()); } +namespace +{ +std::vector<std::string> GetSettingListAsString(const std::string& settingID) +{ + std::vector<CVariant> values = + CServiceBroker::GetSettingsComponent()->GetSettings()->GetList(settingID); + std::vector<std::string> result; + std::transform(values.begin(), values.end(), std::back_inserter(result), + [](CVariant s) { return s.asString(); }); + return result; +} + +const std::map<std::string, std::vector<std::string>> artTypeDefaults = { + {MediaTypeEpisode, {"thumb"}}, + {MediaTypeTvShow, {"poster", "fanart", "banner"}}, + {MediaTypeSeason, {"poster", "fanart", "banner"}}, + {MediaTypeMovie, {"poster", "fanart"}}, + {MediaTypeVideoCollection, {"poster", "fanart"}}, + {MediaTypeMusicVideo, {"poster", "fanart"}}, + {MediaTypeNone, { "poster", "fanart", "banner", "thumb" }}, +}; + +const std::vector<std::string> artTypeDefaultsFallback = {}; + +const std::vector<std::string>& GetArtTypeDefault(const std::string& mediaType) +{ + auto defaults = artTypeDefaults.find(mediaType); + if (defaults != artTypeDefaults.end()) + return defaults->second; + return artTypeDefaultsFallback; +} + +const std::map<std::string, std::string> artTypeSettings = { + {MediaTypeEpisode, CSettings::SETTING_VIDEOLIBRARY_EPISODEART_WHITELIST}, + {MediaTypeTvShow, CSettings::SETTING_VIDEOLIBRARY_TVSHOWART_WHITELIST}, + {MediaTypeSeason, CSettings::SETTING_VIDEOLIBRARY_TVSHOWART_WHITELIST}, + {MediaTypeMovie, CSettings::SETTING_VIDEOLIBRARY_MOVIEART_WHITELIST}, + {MediaTypeVideoCollection, CSettings::SETTING_VIDEOLIBRARY_MOVIEART_WHITELIST}, + {MediaTypeMusicVideo, CSettings::SETTING_VIDEOLIBRARY_MUSICVIDEOART_WHITELIST}, +}; +} // namespace + std::vector<std::string> CVideoThumbLoader::GetArtTypes(const std::string &type) { - const std::shared_ptr<CAdvancedSettings> advancedSettings = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings(); - std::vector<std::string> ret; - if (type == MediaTypeEpisode) - { - ret = {"thumb"}; - for (auto& artType : advancedSettings->m_videoEpisodeExtraArt) - { - if (find(ret.begin(), ret.end(), artType) == ret.end()) - ret.push_back(artType); - } - } - else if (type == MediaTypeTvShow) - { - ret = {"poster", "fanart", "banner"}; - for (auto& artType : advancedSettings->m_videoTvShowExtraArt) - { - if (find(ret.begin(), ret.end(), artType) == ret.end()) - ret.push_back(artType); - } - } - else if (type == MediaTypeSeason) - { - ret = {"poster", "fanart", "banner"}; - for (auto& artType : advancedSettings->m_videoTvSeasonExtraArt) - { - if (find(ret.begin(), ret.end(), artType) == ret.end()) - ret.push_back(artType); - } - } - else if (type == MediaTypeMovie) + int artworkLevel = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt( + CSettings::SETTING_VIDEOLIBRARY_ARTWORK_LEVEL); + if (artworkLevel == CSettings::VIDEOLIBRARY_ARTWORK_LEVEL_NONE) { - ret = {"poster", "fanart"}; - for (auto& artType : advancedSettings->m_videoMovieExtraArt) - { - if (find(ret.begin(), ret.end(), artType) == ret.end()) - ret.push_back(artType); - } + return {}; } - else if (type == MediaTypeVideoCollection) + + std::vector<std::string> result = GetArtTypeDefault(type); + if (artworkLevel != CSettings::VIDEOLIBRARY_ARTWORK_LEVEL_CUSTOM) { - ret = {"poster", "fanart"}; - for (auto& artType : advancedSettings->m_videoMovieSetExtraArt) - { - if (find(ret.begin(), ret.end(), artType) == ret.end()) - ret.push_back(artType); - } + return result; } - else if (type == MediaTypeMusicVideo) + + auto settings = artTypeSettings.find(type); + if (settings == artTypeSettings.end()) + return result; + + for (auto& artType : GetSettingListAsString(settings->second)) { - ret = {"poster", "fanart"}; - for (auto& artType : advancedSettings->m_videoMusicVideoExtraArt) - { - if (find(ret.begin(), ret.end(), artType) == ret.end()) - ret.push_back(artType); - } + if (find(result.begin(), result.end(), artType) == result.end()) + result.push_back(artType); } - else if (type.empty()) // unknown, just the basics - ret = { "poster", "fanart", "banner", "thumb" }; - return ret; + return result; +} + +bool CVideoThumbLoader::IsValidArtType(const std::string& potentialArtType) +{ + return !potentialArtType.empty() && potentialArtType.length() <= 25 && + std::find_if_not( + potentialArtType.begin(), potentialArtType.end(), + StringUtils::isasciialphanum + ) == potentialArtType.end(); +} + +bool CVideoThumbLoader::IsArtTypeInWhitelist(const std::string& artType, const std::vector<std::string>& whitelist, bool exact) +{ + // whitelist contains art "families", 'fanart' also matches 'fanart1', 'fanart2', and so on + std::string compareArtType = artType; + if (!exact) + StringUtils::TrimRight(compareArtType, "0123456789"); + + return std::find(whitelist.begin(), whitelist.end(), compareArtType) != whitelist.end(); } /** diff --git a/xbmc/video/VideoThumbLoader.h b/xbmc/video/VideoThumbLoader.h index 96e0a31b49..3c2d9f0453 100644 --- a/xbmc/video/VideoThumbLoader.h +++ b/xbmc/video/VideoThumbLoader.h @@ -92,6 +92,10 @@ public: */ static std::vector<std::string> GetArtTypes(const std::string &type); + static bool IsValidArtType(const std::string& potentialArtType); + + static bool IsArtTypeInWhitelist(const std::string& artType, const std::vector<std::string>& whitelist, bool exact); + /*! \brief helper function to retrieve a thumb URL for embedded video thumbs \param item a video CFileItem. \return a URL for the embedded thumb. |