diff options
author | Kai Sommerfeld <3226626+ksooo@users.noreply.github.com> | 2023-09-11 08:08:10 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-11 08:08:10 +0200 |
commit | 085a40300fa8c0d20e9591ea224241b9c5a8eee5 (patch) | |
tree | bb6c57ae4a87cc09aa9667fef97ed96938407de9 | |
parent | 327fd819622980f578ebe1a40b9f0520d933712f (diff) | |
parent | 7fe525bacadf704dae1d12c42b63760fe2d403d1 (diff) |
Merge pull request #23734 from ksooo/video-refactor-artwork-selection
[video] Refactor artwork selection (last step)
-rw-r--r-- | addons/resource.language.en_gb/resources/strings.po | 7 | ||||
-rw-r--r-- | xbmc/video/CMakeLists.txt | 2 | ||||
-rw-r--r-- | xbmc/video/VideoItemArtworkHandler.cpp | 554 | ||||
-rw-r--r-- | xbmc/video/VideoItemArtworkHandler.h | 53 | ||||
-rw-r--r-- | xbmc/video/dialogs/GUIDialogVideoInfo.cpp | 589 | ||||
-rw-r--r-- | xbmc/video/dialogs/GUIDialogVideoInfo.h | 10 | ||||
-rw-r--r-- | xbmc/video/tags/CMakeLists.txt | 4 | ||||
-rw-r--r-- | xbmc/video/tags/VideoInfoTagLoaderFactory.cpp | 7 | ||||
-rw-r--r-- | xbmc/video/tags/VideoTagExtractionHelper.cpp | 45 | ||||
-rw-r--r-- | xbmc/video/tags/VideoTagExtractionHelper.h | 41 |
10 files changed, 785 insertions, 527 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 80e144370b..2bfe7e1992 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -13099,6 +13099,7 @@ msgid "Where no local album cover exists, online art will be used. Where neither msgstr "" #: system/settings/settings.xml +#: xbmc/video/VideoItemArtworkHandler.cpp #: xbmc/music/dialogs/GUIDialogVideoInfo.cpp msgctxt "#20226" msgid "Movie set information folder" @@ -18915,7 +18916,8 @@ msgctxt "#36040" msgid "Detected version of libCEC interface ({0:x}) is lower than the supported version {1:x}." msgstr "" -#: xbmc/video/dialogs/guidialogvideoinfo.cpp +#: xbmc/video/VideoItemArtworkHandler.cpp +#: xbmc/video/dialogs/GUIDialogVideoInfo.cpp #: xbmc/music/dialogs/GUIDialogMusicInfo.cpp msgctxt "#36041" msgid "* Item folder" @@ -23066,8 +23068,9 @@ msgctxt "#39122" msgid "Library Information Sources" msgstr "" -#. Label for section of settings +#. Label for section of settings, label for artwork file browse dialog #: system/settings/settings.xml +#: xbmc/video/dialogs/GUIDialogVideoInfo.cpp msgctxt "#39123" msgid "Artwork" msgstr "" diff --git a/xbmc/video/CMakeLists.txt b/xbmc/video/CMakeLists.txt index 1deed57cd0..b5068599b7 100644 --- a/xbmc/video/CMakeLists.txt +++ b/xbmc/video/CMakeLists.txt @@ -3,6 +3,7 @@ set(SOURCES Bookmark.cpp GUIViewStateVideo.cpp PlayerController.cpp Teletext.cpp + VideoItemArtworkHandler.cpp VideoDatabase.cpp VideoDbUrl.cpp VideoEmbeddedImageFileLoader.cpp @@ -22,6 +23,7 @@ set(HEADERS Bookmark.h PlayerController.h Teletext.h TeletextDefines.h + VideoItemArtworkHandler.h VideoDatabase.h VideoDbUrl.h VideoEmbeddedImageFileLoader.h diff --git a/xbmc/video/VideoItemArtworkHandler.cpp b/xbmc/video/VideoItemArtworkHandler.cpp new file mode 100644 index 0000000000..0401c832b3 --- /dev/null +++ b/xbmc/video/VideoItemArtworkHandler.cpp @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2005-2023 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "VideoItemArtworkHandler.h" + +#include "FileItem.h" +#include "MediaSource.h" +#include "ServiceBroker.h" +#include "TextureDatabase.h" +#include "filesystem/Directory.h" +#include "guilib/LocalizeStrings.h" +#include "music/MusicDatabase.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/FileExtensionProvider.h" +#include "utils/FileUtils.h" +#include "utils/URIUtils.h" +#include "utils/Variant.h" +#include "utils/log.h" +#include "video/VideoDatabase.h" +#include "video/VideoInfoScanner.h" +#include "video/VideoInfoTag.h" +#include "video/VideoThumbLoader.h" +#include "video/tags/VideoTagExtractionHelper.h" + +using namespace VIDEO; +using namespace XFILE; + +namespace +{ +//------------------------------------------------------------------------------------------------- +// CVideoItemArtworkHandler (Generic handler) +//------------------------------------------------------------------------------------------------- + +class CVideoItemArtworkHandler : public IVideoItemArtworkHandler +{ +public: + explicit CVideoItemArtworkHandler(const std::shared_ptr<CFileItem>& item, + const std::string& artType) + : m_item(item), m_artType(artType) + { + } + + std::string GetCurrentArt() const override; + std::string GetEmbeddedArt() const override; + std::vector<std::string> GetRemoteArt() const override; + std::string GetLocalArt() const override; + + std::string GetDefaultIcon() const override; + + void AddItemPathToFileBrowserSources(std::vector<CMediaSource>& sources) override; + + void PersistArt(const std::string& art) override; + +protected: + void AddItemPathStringToFileBrowserSources(std::vector<CMediaSource>& sources, + const std::string& itemDir, + const std::string& label); + + const std::shared_ptr<CFileItem> m_item; + const std::string m_artType; +}; + +std::string CVideoItemArtworkHandler::GetCurrentArt() const +{ + if (m_artType.empty()) + { + CLog::LogF(LOGERROR, "Art type not set!"); + return {}; + } + + std::string currentArt; + if (m_item->HasArt(m_artType)) + currentArt = m_item->GetArt(m_artType); + else if (m_item->HasArt("thumb") && (m_artType == "poster" || m_artType == "banner")) + currentArt = m_item->GetArt("thumb"); + + return currentArt; +} + +std::string CVideoItemArtworkHandler::GetEmbeddedArt() const +{ + if (TAGS::CVideoTagExtractionHelper::IsExtractionSupportedFor(*m_item)) + return TAGS::CVideoTagExtractionHelper::ExtractEmbeddedArtFor(*m_item, m_artType); + + return {}; +} + +std::vector<std::string> CVideoItemArtworkHandler::GetRemoteArt() const +{ + std::vector<std::string> remoteArt; + CVideoInfoTag tag(*m_item->GetVideoInfoTag()); + tag.m_strPictureURL.Parse(); + tag.m_strPictureURL.GetThumbUrls(remoteArt, m_artType); + return remoteArt; +} + +std::string CVideoItemArtworkHandler::GetLocalArt() const +{ + return CVideoThumbLoader::GetLocalArt(*m_item, m_artType); +} + +std::string CVideoItemArtworkHandler::GetDefaultIcon() const +{ + return m_item->m_bIsFolder ? "DefaultFolder.png" : "DefaultPicture.png"; +} + +void CVideoItemArtworkHandler::AddItemPathToFileBrowserSources(std::vector<CMediaSource>& sources) +{ + std::string itemDir = m_item->GetVideoInfoTag()->m_basePath; + //season + if (itemDir.empty()) + itemDir = m_item->GetVideoInfoTag()->GetPath(); + + const CFileItem itemTmp(itemDir, false); + if (itemTmp.IsVideo()) + itemDir = URIUtils::GetParentPath(itemDir); + + AddItemPathStringToFileBrowserSources(sources, itemDir, + g_localizeStrings.Get(36041) /* * Item folder */); +} + +void CVideoItemArtworkHandler::PersistArt(const std::string& art) +{ + CVideoDatabase videodb; + if (!videodb.Open()) + { + CLog::LogF(LOGERROR, "Cannot open video database!"); + return; + } + + videodb.SetArtForItem(m_item->GetVideoInfoTag()->m_iDbId, m_item->GetVideoInfoTag()->m_type, + m_artType, art); +} + +void CVideoItemArtworkHandler::AddItemPathStringToFileBrowserSources( + std::vector<CMediaSource>& sources, const std::string& itemDir, const std::string& label) +{ + if (!itemDir.empty() && CDirectory::Exists(itemDir)) + { + CMediaSource itemSource; + itemSource.strName = label; + itemSource.strPath = itemDir; + sources.emplace_back(itemSource); + } +} + +//------------------------------------------------------------------------------------------------- +// CVideoItemArtworkArtistHandler (Artist handler) +//------------------------------------------------------------------------------------------------- + +class CVideoItemArtworkArtistHandler : public CVideoItemArtworkHandler +{ +public: + explicit CVideoItemArtworkArtistHandler(const std::shared_ptr<CFileItem>& item, + const std::string& artType) + : CVideoItemArtworkHandler(item, artType) + { + } + + std::string GetCurrentArt() const override; + std::vector<std::string> GetRemoteArt() const override; + std::string GetLocalArt() const override; + + std::string GetDefaultIcon() const override { return "DefaultArtist.png"; } + + void PersistArt(const std::string& art) override; +}; + +std::string CVideoItemArtworkArtistHandler::GetCurrentArt() const +{ + CMusicDatabase musicdb; + if (!musicdb.Open()) + { + CLog::LogF(LOGERROR, "Cannot open music database!"); + return {}; + } + + std::string currentArt; + const int idArtist = musicdb.GetArtistByName(m_item->GetLabel()); + if (idArtist >= 0) + currentArt = musicdb.GetArtForItem(idArtist, MediaTypeArtist, "thumb"); + + if (currentArt.empty()) + { + CVideoDatabase videodb; + if (!videodb.Open()) + { + CLog::LogF(LOGERROR, "Cannot open video database!"); + return {}; + } + + currentArt = videodb.GetArtForItem(m_item->GetVideoInfoTag()->m_iDbId, + m_item->GetVideoInfoTag()->m_type, "thumb"); + } + return currentArt; +} + +std::vector<std::string> CVideoItemArtworkArtistHandler::GetRemoteArt() const +{ + return {}; +} + +std::string CVideoItemArtworkArtistHandler::GetLocalArt() const +{ + CMusicDatabase musicdb; + if (!musicdb.Open()) + { + CLog::LogF(LOGERROR, "Cannot open music database!"); + return {}; + } + + std::string localArt; + const int idArtist = musicdb.GetArtistByName(m_item->GetLabel()); + if (idArtist >= 0) + { + // Get artist paths - possible locations for thumb - while music db open + CArtist artist; + musicdb.GetArtist(idArtist, artist); + std::string artistPath; + musicdb.GetArtistPath(artist, artistPath); // Artist path in artist info folder + + std::string thumb; + bool existsThumb = false; + + // First look for artist thumb in the primary location + if (!artistPath.empty()) + { + thumb = URIUtils::AddFileToFolder(artistPath, "folder.jpg"); + existsThumb = CFileUtils::Exists(thumb); + } + // If not there fall back local to music files (historic location for those album artists with a unique folder) + if (!existsThumb) + { + std::string artistOldPath; + musicdb.GetOldArtistPath(idArtist, artistOldPath); // Old artist path, local to music files + if (!artistOldPath.empty()) + { + thumb = URIUtils::AddFileToFolder(artistOldPath, "folder.jpg"); + existsThumb = CFileUtils::Exists(thumb); + } + } + + if (existsThumb) + localArt = thumb; + } + return localArt; +} + +void CVideoItemArtworkArtistHandler::PersistArt(const std::string& art) +{ + CMusicDatabase musicdb; + if (!musicdb.Open()) + { + CLog::LogF(LOGERROR, "Cannot open music database!"); + return; + } + + const int idArtist = musicdb.GetArtistByName(m_item->GetLabel()); + if (idArtist >= 0) + musicdb.SetArtForItem(idArtist, MediaTypeArtist, m_artType, art); +} + +//------------------------------------------------------------------------------------------------- +// CVideoItemArtworkActorHandler (Actor handler) +//------------------------------------------------------------------------------------------------- + +class CVideoItemArtworkActorHandler : public CVideoItemArtworkHandler +{ +public: + explicit CVideoItemArtworkActorHandler(const std::shared_ptr<CFileItem>& item, + const std::string& artType) + : CVideoItemArtworkHandler(item, artType) + { + } + + std::string GetCurrentArt() const override; + std::string GetLocalArt() const override; + + std::string GetDefaultIcon() const override { return "DefaultActor.png"; } +}; + +std::string CVideoItemArtworkActorHandler::GetCurrentArt() const +{ + CVideoDatabase videodb; + if (!videodb.Open()) + { + CLog::LogF(LOGERROR, "Cannot open video database!"); + return {}; + } + + return videodb.GetArtForItem(m_item->GetVideoInfoTag()->m_iDbId, + m_item->GetVideoInfoTag()->m_type, "thumb"); +} + +std::string CVideoItemArtworkActorHandler::GetLocalArt() const +{ + std::string localArt; + std::string picturePath; + const std::string thumb = URIUtils::AddFileToFolder(picturePath, "folder.jpg"); + if (CFileUtils::Exists(thumb)) + localArt = thumb; + + return localArt; +} + +//------------------------------------------------------------------------------------------------- +// CVideoItemArtworkSeasonHandler (Season handler) +//------------------------------------------------------------------------------------------------- + +class CVideoItemArtworkSeasonHandler : public CVideoItemArtworkHandler +{ +public: + explicit CVideoItemArtworkSeasonHandler(const std::shared_ptr<CFileItem>& item, + const std::string& artType) + : CVideoItemArtworkHandler(item, artType) + { + } + + std::vector<std::string> GetRemoteArt() const override; +}; + +std::vector<std::string> CVideoItemArtworkSeasonHandler::GetRemoteArt() const +{ + CVideoDatabase videodb; + if (!videodb.Open()) + { + CLog::LogF(LOGERROR, "Cannot open video database!"); + return {}; + } + + std::vector<std::string> remoteArt; + CVideoInfoTag tag; + videodb.GetTvShowInfo("", tag, m_item->GetVideoInfoTag()->m_iIdShow); + tag.m_strPictureURL.Parse(); + tag.m_strPictureURL.GetThumbUrls(remoteArt, m_artType, m_item->GetVideoInfoTag()->m_iSeason); + return remoteArt; +} + +//------------------------------------------------------------------------------------------------- +// CVideoItemArtworkMovieSetHandler (Movie set handler) +//------------------------------------------------------------------------------------------------- + +class CVideoItemArtworkMovieSetHandler : public CVideoItemArtworkHandler +{ +public: + explicit CVideoItemArtworkMovieSetHandler(const std::shared_ptr<CFileItem>& item, + const std::string& artType) + : CVideoItemArtworkHandler(item, artType) + { + } + + std::vector<std::string> GetRemoteArt() const override; + std::string GetLocalArt() const override; + + std::string GetDefaultIcon() const override { return "DefaultVideo.png"; } + + void AddItemPathToFileBrowserSources(std::vector<CMediaSource>& sources) override; +}; + +std::vector<std::string> CVideoItemArtworkMovieSetHandler::GetRemoteArt() const +{ + CVideoDatabase videodb; + if (!videodb.Open()) + { + CLog::LogF(LOGERROR, "Cannot open video database!"); + return {}; + } + + std::vector<std::string> remoteArt; + const std::string baseDir = + StringUtils::Format("videodb://movies/sets/{}", m_item->GetVideoInfoTag()->m_iDbId); + CFileItemList items; + if (videodb.GetMoviesNav(baseDir, items)) + { + for (const auto& item : items) + { + CVideoInfoTag* videotag = item->GetVideoInfoTag(); + videotag->m_strPictureURL.Parse(); + videotag->m_strPictureURL.GetThumbUrls(remoteArt, "set." + m_artType, -1, true); + } + } + return remoteArt; +} + +std::string CVideoItemArtworkMovieSetHandler::GetLocalArt() const +{ + std::string localArt; + const std::string infoFolder = + VIDEO::CVideoInfoScanner::GetMovieSetInfoFolder(m_item->GetLabel()); + if (!infoFolder.empty()) + { + CFileItemList availableArtFiles; + CDirectory::GetDirectory(infoFolder, availableArtFiles, + CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), + DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); + for (const auto& artFile : availableArtFiles) + { + std::string candidate = URIUtils::GetFileName(artFile->GetDynPath()); + URIUtils::RemoveExtension(candidate); + if (StringUtils::EqualsNoCase(candidate, m_artType)) + { + localArt = artFile->GetDynPath(); + break; + } + } + } + return localArt; +} + +void CVideoItemArtworkMovieSetHandler::AddItemPathToFileBrowserSources( + std::vector<CMediaSource>& sources) +{ + AddItemPathStringToFileBrowserSources( + sources, VIDEO::CVideoInfoScanner::GetMovieSetInfoFolder(m_item->GetLabel()), + g_localizeStrings.Get(36041) /* * Item folder */); + AddItemPathStringToFileBrowserSources( + sources, + CServiceBroker::GetSettingsComponent()->GetSettings()->GetString( + CSettings::SETTING_VIDEOLIBRARY_MOVIESETSFOLDER), + "* " + g_localizeStrings.Get(20226) /* Movie set information folder */); +} + +//------------------------------------------------------------------------------------------------- +// CVideoItemArtworkFanartHandler (Handler for all media types, to manage fanart art type) +//------------------------------------------------------------------------------------------------- + +class CVideoItemArtworkFanartHandler : public CVideoItemArtworkHandler +{ +public: + explicit CVideoItemArtworkFanartHandler(const std::shared_ptr<CFileItem>& item, + const std::string& artType) + : CVideoItemArtworkHandler(item, artType) + { + // Ensure the fanart is unpacked + m_item->GetVideoInfoTag()->m_fanart.Unpack(); + } + + std::string GetCurrentArt() const override; + std::vector<std::string> GetRemoteArt() const override; + std::string GetLocalArt() const override; + + std::string GetDefaultIcon() const override { return "DefaultPicture.png"; } + bool SupportsFlippedArt() const override { return true; } + + std::string UpdateEmbeddedArt(const std::string& art) override; + std::string UpdateRemoteArt(const std::vector<std::string>& art, int index) override; +}; + +std::string CVideoItemArtworkFanartHandler::GetCurrentArt() const +{ + return m_item->GetArt("fanart"); +} + +std::vector<std::string> CVideoItemArtworkFanartHandler::GetRemoteArt() const +{ + std::vector<std::string> remoteArt; + const CVideoInfoTag* videoTag = m_item->GetVideoInfoTag(); + for (unsigned int i = 0; i < videoTag->m_fanart.GetNumFanarts(); ++i) + { + const std::string thumb = videoTag->m_fanart.GetPreviewURL(i); + if (URIUtils::IsProtocol(thumb, "image")) + continue; + + remoteArt.emplace_back(CTextureUtils::GetWrappedThumbURL(thumb)); + } + return remoteArt; +} + +std::string CVideoItemArtworkFanartHandler::GetLocalArt() const +{ + return m_item->GetLocalFanart(); +} + +std::string CVideoItemArtworkFanartHandler::UpdateEmbeddedArt(const std::string& art) +{ + CVideoDatabase videodb; + if (!videodb.Open()) + { + CLog::LogF(LOGERROR, "Cannot open video database!"); + return art; + } + + CVideoInfoTag* videoTag = m_item->GetVideoInfoTag(); + const int currentTag = videoTag->m_fanart.GetNumFanarts(); + int matchingTag = -1; + for (int i = 0; i < currentTag; ++i) + { + if (URIUtils::IsProtocol(videoTag->m_fanart.GetImageURL(i), "image")) + matchingTag = i; + } + + if (matchingTag != -1) + { + videoTag->m_fanart.AddFanart(art, "", ""); + matchingTag = currentTag; + } + + videoTag->m_fanart.SetPrimaryFanart(matchingTag); + videodb.UpdateFanart(*m_item, m_item->GetVideoContentType()); + return art; +} + +std::string CVideoItemArtworkFanartHandler::UpdateRemoteArt(const std::vector<std::string>& art, + int index) +{ + CVideoInfoTag* videoTag = m_item->GetVideoInfoTag(); + + CVideoDatabase videodb; + if (!videodb.Open()) + { + CLog::LogF(LOGERROR, "Cannot open video database!"); + } + else + { + videoTag->m_fanart.SetPrimaryFanart(index); + videodb.UpdateFanart(*m_item, m_item->GetVideoContentType()); + } + return videoTag->m_fanart.GetImageURL(); +} + +} // unnamed namespace + +//------------------------------------------------------------------------------------------------- +// IVideoItemArtworkHandlerFactory +//------------------------------------------------------------------------------------------------- + +std::unique_ptr<IVideoItemArtworkHandler> IVideoItemArtworkHandlerFactory::Create( + const std::shared_ptr<CFileItem>& item, + const std::string& mediaType, + const std::string& artType) +{ + std::unique_ptr<IVideoItemArtworkHandler> artHandler; + + if (artType == "fanart" && mediaType != MediaTypeVideoCollection) + artHandler = std::make_unique<CVideoItemArtworkFanartHandler>(item, artType); + else if (mediaType == MediaTypeArtist) + artHandler = std::make_unique<CVideoItemArtworkArtistHandler>(item, artType); + else if (mediaType == "actor") + artHandler = std::make_unique<CVideoItemArtworkActorHandler>(item, artType); + else if (mediaType == MediaTypeSeason) + artHandler = std::make_unique<CVideoItemArtworkSeasonHandler>(item, artType); + else if (mediaType == MediaTypeVideoCollection) + artHandler = std::make_unique<CVideoItemArtworkMovieSetHandler>(item, artType); + else + artHandler = std::make_unique<CVideoItemArtworkHandler>(item, artType); + + return artHandler; +} diff --git a/xbmc/video/VideoItemArtworkHandler.h b/xbmc/video/VideoItemArtworkHandler.h new file mode 100644 index 0000000000..01613ef7d0 --- /dev/null +++ b/xbmc/video/VideoItemArtworkHandler.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005-2023 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include <memory> +#include <string> +#include <vector> + +class CFileItem; +class CMediaSource; + +namespace VIDEO +{ +class IVideoItemArtworkHandler +{ +public: + virtual ~IVideoItemArtworkHandler() = default; + + virtual std::string GetCurrentArt() const = 0; + + virtual std::string GetEmbeddedArt() const { return {}; } + virtual std::vector<std::string> GetRemoteArt() const { return {}; } + virtual std::string GetLocalArt() const { return {}; } + + virtual std::string GetDefaultIcon() const = 0; + virtual bool SupportsFlippedArt() const { return false; } + + virtual void AddItemPathToFileBrowserSources(std::vector<CMediaSource>& sources) {} + + virtual std::string UpdateEmbeddedArt(const std::string& art) { return art; } + virtual std::string UpdateRemoteArt(const std::vector<std::string>& art, int index) + { + return art[index]; + } + + virtual void PersistArt(const std::string& art) = 0; +}; + +class IVideoItemArtworkHandlerFactory +{ +public: + static std::unique_ptr<IVideoItemArtworkHandler> Create(const std::shared_ptr<CFileItem>& item, + const std::string& mediaType, + const std::string& artType); +}; + +} // namespace VIDEO diff --git a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp index 233fe7606a..2ded282183 100644 --- a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp @@ -41,7 +41,6 @@ #include "settings/SettingsComponent.h" #include "settings/lib/Setting.h" #include "storage/MediaManager.h" -#include "utils/FileExtensionProvider.h" #include "utils/FileUtils.h" #include "utils/SortUtils.h" #include "utils/StringUtils.h" @@ -50,10 +49,10 @@ #include "video/VideoDbUrl.h" #include "video/VideoInfoScanner.h" #include "video/VideoInfoTag.h" +#include "video/VideoItemArtworkHandler.h" #include "video/VideoLibraryQueue.h" #include "video/VideoThumbLoader.h" #include "video/VideoUtils.h" -#include "video/tags/VideoTagLoaderFFmpeg.h" #include "video/windows/GUIWindowVideoNav.h" #include <iterator> @@ -879,184 +878,24 @@ std::string CGUIDialogVideoInfo::ChooseArtType(const CFileItem &videoItem) void CGUIDialogVideoInfo::OnGetArt() { - bool finished = false; - while (!finished) + if (ChooseAndManageVideoItemArtwork(m_movieItem)) { - if (ManageVideoItemArtwork(m_movieItem, m_movieItem->GetVideoInfoTag()->m_type, finished)) - { - m_hasUpdatedThumb = true; - - // Update our screen - Update(); - } - }; -} + m_hasUpdatedThumb = true; -namespace -{ -std::string GetEmbeddedArt(const std::string& fileNameAndPath, const std::string& artType) -{ - std::string embeddedArt; - if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( - CSettings::SETTING_MYVIDEOS_USETAGS)) - { - if (URIUtils::HasExtension(fileNameAndPath, ".mkv") || - URIUtils::HasExtension(fileNameAndPath, ".mp4") || - URIUtils::HasExtension(fileNameAndPath, ".avi") || - URIUtils::HasExtension(fileNameAndPath, ".m4v")) - { - CFileItem item(fileNameAndPath, false); - CVideoTagLoaderFFmpeg loader(item, nullptr, false); - CVideoInfoTag tag; - loader.Load(tag, false, nullptr); - for (const auto& it : tag.m_coverArt) - { - if (it.m_type == artType) - { - embeddedArt = CTextureUtils::GetWrappedImageURL(fileNameAndPath, "video_" + artType); - break; - } - } - } + // Update our screen + Update(); } - return embeddedArt; } -} // unnamed namespace - -// Allow user to select a Fanart void CGUIDialogVideoInfo::OnGetFanart() { - CFileItemList items; - - // Ensure the fanart is unpacked - m_movieItem->GetVideoInfoTag()->m_fanart.Unpack(); - - if (m_movieItem->HasArt("fanart")) - { - CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false)); - itemCurrent->SetArt("thumb", m_movieItem->GetArt("fanart")); - itemCurrent->SetArt("icon", "DefaultPicture.png"); - itemCurrent->SetLabel(g_localizeStrings.Get(20440)); - items.Add(itemCurrent); - } - - const std::string embeddedArt = - GetEmbeddedArt(m_movieItem->GetVideoInfoTag()->m_strFileNameAndPath, "fanart"); - if (!embeddedArt.empty()) - { - const auto itemEmbedded = std::make_shared<CFileItem>("fanart://Embedded", false); - itemEmbedded->SetArt("thumb", embeddedArt); - itemEmbedded->SetLabel(g_localizeStrings.Get(13520)); - items.Add(itemEmbedded); - } - - // Grab the thumbnails from the web - for (unsigned int i = 0; i < m_movieItem->GetVideoInfoTag()->m_fanart.GetNumFanarts(); i++) - { - if (URIUtils::IsProtocol(m_movieItem->GetVideoInfoTag()->m_fanart.GetPreviewURL(i), "image")) - continue; - std::string strItemPath = StringUtils::Format("fanart://Remote{}", i); - CFileItemPtr item(new CFileItem(strItemPath, false)); - std::string thumb = m_movieItem->GetVideoInfoTag()->m_fanart.GetPreviewURL(i); - item->SetArt("thumb", CTextureUtils::GetWrappedThumbURL(thumb)); - item->SetArt("icon", "DefaultPicture.png"); - item->SetLabel(g_localizeStrings.Get(20441)); - - //! @todo Do we need to clear the cached image? - // CServiceBroker::GetTextureCache()->ClearCachedImage(thumb); - items.Add(item); - } - - CFileItem item(*m_movieItem->GetVideoInfoTag()); - std::string strLocal = item.GetLocalFanart(); - if (!strLocal.empty()) + if (ManageVideoItemArtwork(m_movieItem, m_movieItem->GetVideoInfoTag()->m_type, "fanart")) { - CFileItemPtr itemLocal(new CFileItem("fanart://Local",false)); - itemLocal->SetArt("thumb", strLocal); - itemLocal->SetArt("icon", "DefaultPicture.png"); - itemLocal->SetLabel(g_localizeStrings.Get(20438)); + m_hasUpdatedThumb = true; - //! @todo Do we need to clear the cached image? - CServiceBroker::GetTextureCache()->ClearCachedImage(strLocal); - items.Add(itemLocal); - } - else - { - CFileItemPtr itemNone(new CFileItem("fanart://None", false)); - itemNone->SetArt("icon", "DefaultPicture.png"); - itemNone->SetLabel(g_localizeStrings.Get(20439)); - items.Add(itemNone); + // Update our screen + Update(); } - - std::string result; - VECSOURCES sources(*CMediaSourceSettings::GetInstance().GetSources("video")); - AddItemPathToFileBrowserSources(sources, item); - CServiceBroker::GetMediaManager().GetLocalDrives(sources); - bool flip=false; - if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || - StringUtils::EqualsNoCase(result, "fanart://Current")) - return; // user cancelled - - if (StringUtils::EqualsNoCase(result, "fanart://Local")) - result = strLocal; - - if (StringUtils::EqualsNoCase(result, "fanart://Embedded")) - { - unsigned int current = m_movieItem->GetVideoInfoTag()->m_fanart.GetNumFanarts(); - int found = -1; - for (size_t i = 0; i < current; ++i) - if (URIUtils::IsProtocol(m_movieItem->GetVideoInfoTag()->m_fanart.GetImageURL(), "image")) - found = i; - if (found != -1) - { - m_movieItem->GetVideoInfoTag()->m_fanart.AddFanart(embeddedArt, "", ""); - found = current; - } - - m_movieItem->GetVideoInfoTag()->m_fanart.SetPrimaryFanart(found); - - CVideoDatabase db; - if (db.Open()) - { - db.UpdateFanart(*m_movieItem, m_movieItem->GetVideoContentType()); - db.Close(); - } - result = embeddedArt; - } - - if (StringUtils::StartsWith(result, "fanart://Remote")) - { - int iFanart = atoi(result.substr(15).c_str()); - // set new primary fanart, and update our database accordingly - m_movieItem->GetVideoInfoTag()->m_fanart.SetPrimaryFanart(iFanart); - CVideoDatabase db; - if (db.Open()) - { - db.UpdateFanart(*m_movieItem, m_movieItem->GetVideoContentType()); - db.Close(); - } - result = m_movieItem->GetVideoInfoTag()->m_fanart.GetImageURL(); - } - else if (StringUtils::EqualsNoCase(result, "fanart://None") || !CFileUtils::Exists(result)) - result.clear(); - - // set the fanart image - if (flip && !result.empty()) - result = CTextureUtils::GetWrappedImageURL(result, "", "flipped"); - CVideoDatabase db; - if (db.Open()) - { - db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, "fanart", result); - db.Close(); - } - - CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show - m_movieItem->SetArt("fanart", result); - m_hasUpdatedThumb = true; - - // Update our screen - Update(); } void CGUIDialogVideoInfo::OnSetUserrating() const @@ -1105,45 +944,6 @@ std::string CGUIDialogVideoInfo::GetThumbnail() const return m_movieItem->GetArt("thumb"); } -namespace -{ -std::string GetItemPathForBrowserSource(const CFileItem& item) -{ - if (!item.HasVideoInfoTag()) - return ""; - - std::string itemDir = item.GetVideoInfoTag()->m_basePath; - //season - if (itemDir.empty()) - itemDir = item.GetVideoInfoTag()->GetPath(); - - CFileItem itemTmp(itemDir, false); - if (itemTmp.IsVideo()) - itemDir = URIUtils::GetParentPath(itemDir); - - return itemDir; -} - -void AddItemPathStringToFileBrowserSources(VECSOURCES& sources, - const std::string& itemDir, const std::string& label) -{ - if (!itemDir.empty() && CDirectory::Exists(itemDir)) - { - CMediaSource itemSource; - itemSource.strName = label; - itemSource.strPath = itemDir; - sources.push_back(itemSource); - } -} -} // namespace - -void CGUIDialogVideoInfo::AddItemPathToFileBrowserSources(VECSOURCES& sources, - const CFileItem& item) -{ - std::string itemDir = GetItemPathForBrowserSource(item); - AddItemPathStringToFileBrowserSources(sources, itemDir, g_localizeStrings.Get(36041)); -} - int CGUIDialogVideoInfo::ManageVideoItem(const std::shared_ptr<CFileItem>& item) { if (item == nullptr || !item->IsVideoDb() || !item->HasVideoInfoTag() || item->GetVideoInfoTag()->m_iDbId < 0) @@ -1259,7 +1059,7 @@ int CGUIDialogVideoInfo::ManageVideoItem(const std::shared_ptr<CFileItem>& item) break; case CONTEXT_BUTTON_SET_ART: - result = ManageVideoItemArtwork(item, type); + result = ChooseAndManageVideoItemArtwork(item); break; case CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS: @@ -1878,128 +1678,51 @@ bool CGUIDialogVideoInfo::RemoveItemsFromTag(const std::shared_ptr<CFileItem>& t return true; } -namespace -{ -std::string FindLocalMovieSetArtworkFile(const CFileItemPtr& item, const std::string& artType) -{ - std::string infoFolder = VIDEO::CVideoInfoScanner::GetMovieSetInfoFolder(item->GetLabel()); - if (infoFolder.empty()) - return ""; - - CFileItemList availableArtFiles; - CDirectory::GetDirectory(infoFolder, availableArtFiles, - CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), - DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); - for (const auto& artFile : availableArtFiles) - { - std::string candidate = URIUtils::GetFileName(artFile->GetPath()); - URIUtils::RemoveExtension(candidate); - if (StringUtils::EqualsNoCase(candidate, artType)) - return artFile->GetPath(); - } - return ""; -} -} // namespace - -bool CGUIDialogVideoInfo::ManageVideoItemArtwork(const std::shared_ptr<CFileItem>& item, - const MediaType& type) +bool CGUIDialogVideoInfo::ChooseAndManageVideoItemArtwork(const std::shared_ptr<CFileItem>& item) { bool result = false; - bool finished = false; - while (!finished) + std::string artType; + do { - result = ManageVideoItemArtwork(item, type, finished); - } + artType = ChooseArtType(*item); + if (!artType.empty()) + result = ManageVideoItemArtwork(item, item->GetVideoInfoTag()->m_type, artType); + + } while (!artType.empty()); return result; } bool CGUIDialogVideoInfo::ManageVideoItemArtwork(const std::shared_ptr<CFileItem>& item, - const MediaType& type, - bool& finished) + const std::string& mediaType) { - finished = true; + // When not selecting art type, default type to "thumb". + return ManageVideoItemArtwork(item, mediaType, "thumb"); +} - if (item == nullptr || !item->HasVideoInfoTag() || type.empty()) +bool CGUIDialogVideoInfo::ManageVideoItemArtwork(const std::shared_ptr<CFileItem>& item, + const MediaType& mediaType, + const std::string& artType) +{ + if (item == nullptr || !item->HasVideoInfoTag() || mediaType.empty() || artType.empty()) return false; - CVideoDatabase videodb; - if (!videodb.Open()) - return false; + const std::unique_ptr<VIDEO::IVideoItemArtworkHandler> artHandler = + VIDEO::IVideoItemArtworkHandlerFactory::Create(item, mediaType, artType); - // Grab the thumbnails from the web CFileItemList items; - CFileItemPtr noneitem(new CFileItem("thumb://None", false)); - std::string currentThumb; - int idArtist = -1; - std::string artistPath; - std::string artistOldPath; - std::string artType = "thumb"; - if (type == MediaTypeArtist) - { - CMusicDatabase musicdb; - if (musicdb.Open()) - { - idArtist = musicdb.GetArtistByName(item->GetLabel()); // Fails when name not unique - if (idArtist >= 0 ) - { - // Get artist paths - possible locations for thumb - while music db open - musicdb.GetOldArtistPath(idArtist, artistOldPath); // Old artist path, local to music files - CArtist artist; - musicdb.GetArtist(idArtist, artist); // Need name and mbid for artist folder name - musicdb.GetArtistPath(artist, artistPath); // Artist path in artist info folder - - currentThumb = musicdb.GetArtForItem(idArtist, MediaTypeArtist, "thumb"); - if (currentThumb.empty()) - currentThumb = videodb.GetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artType); - } - } - } - else if (type == "actor") - { - currentThumb = videodb.GetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artType); - } - else - { // SEASON, SHOW, SET - - // We want to re-open the art type selection dialog after selecting an image for the type - // until user canceled the art type selection dialog, controlled via 'finished' value by - // the caller of this method. - - artType = ChooseArtType(*item); - if (artType.empty()) - { - finished = true; - return false; - } - finished = false; - - if (artType == "fanart" && type != MediaTypeVideoCollection) - { - const bool result = OnGetFanart(item); - return result; - } - - if (item->HasArt(artType)) - currentThumb = item->GetArt(artType); - else if ((artType == "poster" || artType == "banner") && item->HasArt("thumb")) - currentThumb = item->GetArt("thumb"); - } - - if (!currentThumb.empty()) + const std::string currentArt = artHandler->GetCurrentArt(); + if (!currentArt.empty()) { - CFileItemPtr item(new CFileItem("thumb://Current", false)); - item->SetArt("thumb", currentThumb); - item->SetLabel(g_localizeStrings.Get(13512)); - items.Add(item); + const auto itemCurrent = std::make_shared<CFileItem>("thumb://Current", false); + itemCurrent->SetArt("thumb", currentArt); + itemCurrent->SetLabel(g_localizeStrings.Get(13512)); + items.Add(itemCurrent); } - noneitem->SetArt("icon", item->m_bIsFolder ? "DefaultFolder.png" : "DefaultPicture.png"); - noneitem->SetLabel(g_localizeStrings.Get(13515)); - const std::string embeddedArt = - GetEmbeddedArt(item->GetVideoInfoTag()->m_strFileNameAndPath, artType); + const std::string embeddedArt = artHandler->GetEmbeddedArt(); if (!embeddedArt.empty()) { const auto itemEmbedded = std::make_shared<CFileItem>("thumb://Embedded", false); @@ -2008,180 +1731,75 @@ bool CGUIDialogVideoInfo::ManageVideoItemArtwork(const std::shared_ptr<CFileItem items.Add(itemEmbedded); } - std::string localThumb; - - bool local = false; - std::vector<std::string> thumbs; - if (type != MediaTypeArtist) + std::vector<std::string> remoteArt = artHandler->GetRemoteArt(); + for (size_t i = 0; i < remoteArt.size(); ++i) { - CVideoInfoTag tag; - if (type == MediaTypeSeason) - { - videodb.GetTvShowInfo("", tag, item->GetVideoInfoTag()->m_iIdShow); - tag.m_strPictureURL.Parse(); - tag.m_strPictureURL.GetThumbUrls(thumbs, artType, item->GetVideoInfoTag()->m_iSeason); - } - else if (type == MediaTypeVideoCollection) - { - CFileItemList items; - std::string baseDir = - StringUtils::Format("videodb://movies/sets/{}", item->GetVideoInfoTag()->m_iDbId); - if (videodb.GetMoviesNav(baseDir, items)) - { - for (int i=0; i < items.Size(); i++) - { - CVideoInfoTag* pTag = items[i]->GetVideoInfoTag(); - pTag->m_strPictureURL.Parse(); - pTag->m_strPictureURL.GetThumbUrls(thumbs, "set." + artType, -1, true); - } - } - } - else - { - tag = *item->GetVideoInfoTag(); - tag.m_strPictureURL.Parse(); - tag.m_strPictureURL.GetThumbUrls(thumbs, artType); - } + const auto itemRemote = + std::make_shared<CFileItem>(StringUtils::Format("thumb://Remote{0}", i), false); + itemRemote->SetArt("thumb", remoteArt[i]); + itemRemote->SetArt("icon", "DefaultPicture.png"); + itemRemote->SetLabel(g_localizeStrings.Get(13513)); + items.Add(itemRemote); - for (size_t i = 0; i < thumbs.size(); i++) - { - CFileItemPtr item(new CFileItem(StringUtils::Format("thumb://Remote{0}", i), false)); - item->SetArt("thumb", thumbs[i]); - item->SetArt("icon", "DefaultPicture.png"); - item->SetLabel(g_localizeStrings.Get(13513)); - items.Add(item); - - //! @todo Do we need to clear the cached image? - // CServiceBroker::GetTextureCache()->ClearCachedImage(thumbs[i]); - } - - if (type == "actor") - { - std::string picturePath; - std::string strThumb = URIUtils::AddFileToFolder(picturePath, "folder.jpg"); - if (CFileUtils::Exists(strThumb)) - { - CFileItemPtr pItem(new CFileItem(strThumb,false)); - pItem->SetLabel(g_localizeStrings.Get(13514)); - pItem->SetArt("thumb", strThumb); - items.Add(pItem); - local = true; - } - else - noneitem->SetArt("icon", "DefaultActor.png"); - } - else if (type == MediaTypeVideoCollection) - { - std::string localFile = FindLocalMovieSetArtworkFile(item, artType); - if (!localFile.empty()) - { - CFileItemPtr pItem(new CFileItem(localFile, false)); - pItem->SetLabel(g_localizeStrings.Get(13514)); - pItem->SetArt("thumb", localFile); - items.Add(pItem); - local = true; - } - else - noneitem->SetArt("icon", "DefaultVideo.png"); - } - else - { - localThumb = CVideoThumbLoader::GetLocalArt(*item, artType); - if (!localThumb.empty()) - { - const auto localitem = std::make_shared<CFileItem>("thumb://Local", false); - localitem->SetArt("thumb", localThumb); - localitem->SetArt("icon", "DefaultPicture.png"); - localitem->SetLabel(g_localizeStrings.Get(13514)); - items.Add(localitem); - } - else - noneitem->SetArt("icon", "DefaultPicture.png"); - } + //! @todo Do we need to clear the cached image? + // CServiceBroker::GetTextureCache()->ClearCachedImage(remoteArt[i]); } - else - { - std::string strThumb; - bool existsThumb = false; - // First look for artist thumb in the primary location - if (!artistPath.empty()) - { - strThumb = URIUtils::AddFileToFolder(artistPath, "folder.jpg"); - existsThumb = CFileUtils::Exists(strThumb); - } - // If not there fall back local to music files (historic location for those album artists with a unique folder) - if (!existsThumb && !artistOldPath.empty()) - { - strThumb = URIUtils::AddFileToFolder(artistOldPath, "folder.jpg"); - existsThumb = CFileUtils::Exists(strThumb); - } - if (existsThumb) - { - CFileItemPtr pItem(new CFileItem(strThumb, false)); - pItem->SetLabel(g_localizeStrings.Get(13514)); - pItem->SetArt("thumb", strThumb); - items.Add(pItem); - local = true; - } - else - noneitem->SetArt("icon", "DefaultArtist.png"); + const std::string localArt = artHandler->GetLocalArt(); + if (!localArt.empty()) + { + const auto itemLocal = std::make_shared<CFileItem>("thumb://Local", false); + itemLocal->SetLabel(g_localizeStrings.Get(13514)); + itemLocal->SetArt("thumb", localArt); + items.Add(itemLocal); } - if (!local) - items.Add(noneitem); + const auto itemNone = std::make_shared<CFileItem>("thumb://None", false); + itemNone->SetLabel(g_localizeStrings.Get(13515)); + itemNone->SetArt("icon", artHandler->GetDefaultIcon()); + items.Add(itemNone); std::string result; - VECSOURCES sources=*CMediaSourceSettings::GetInstance().GetSources("video"); + std::vector<CMediaSource> sources = *CMediaSourceSettings::GetInstance().GetSources("video"); CServiceBroker::GetMediaManager().GetLocalDrives(sources); - if (type == MediaTypeVideoCollection) - { - AddItemPathStringToFileBrowserSources(sources, - VIDEO::CVideoInfoScanner::GetMovieSetInfoFolder(item->GetLabel()), - g_localizeStrings.Get(36041)); - AddItemPathStringToFileBrowserSources(sources, - CServiceBroker::GetSettingsComponent()->GetSettings()->GetString( - CSettings::SETTING_VIDEOLIBRARY_MOVIESETSFOLDER), - "* " + g_localizeStrings.Get(20226)); - } - else - AddItemPathToFileBrowserSources(sources, *item); + artHandler->AddItemPathToFileBrowserSources(sources); - if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(13511), result)) - return false; // user cancelled + bool flip = false; + if (!CGUIDialogFileBrowser::ShowAndGetImage( + items, sources, g_localizeStrings.Get(13511) /* Choose art */, result, + artHandler->SupportsFlippedArt() ? &flip : nullptr, 39123 /* Artwork */)) + return false; // user cancelled if (result == "thumb://Current") - result = currentThumb; // user chose the one they have + result = currentArt; // user chose the one they have if (result == "thumb://Local") - result = localThumb; + result = localArt; if (result == "thumb://Embedded") - result = embeddedArt; + result = artHandler->UpdateEmbeddedArt(embeddedArt); // delete the thumbnail if that's what the user wants, else overwrite with the // new thumbnail if (result == "thumb://None") + { result.clear(); + } else if (StringUtils::StartsWith(result, "thumb://Remote")) { - int number = atoi(StringUtils::Mid(result, 14).c_str()); - result = thumbs[number]; + const int index = std::atoi(StringUtils::Mid(result, 14).c_str()); + result = artHandler->UpdateRemoteArt(remoteArt, index); } + // flip selected image, if user wants it + if (!result.empty() && flip) + result = CTextureUtils::GetWrappedImageURL(result, "", "flipped"); + // write the selected artwork to the database - if (type != MediaTypeArtist || idArtist < 0) - { - videodb.SetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artType, result); - } - else - { - CMusicDatabase musicdb; - if (musicdb.Open()) - musicdb.SetArtForItem(idArtist, MediaTypeArtist, artType, result); - } + artHandler->PersistArt(result); item->SetArt(artType, result); + if (item->HasProperty("set_folder_thumb")) { // have a folder thumb to set as well @@ -2310,59 +1928,6 @@ bool CGUIDialogVideoInfo::LinkMovieToTvShow(const std::shared_ptr<CFileItem>& it return false; } -bool CGUIDialogVideoInfo::OnGetFanart(const std::shared_ptr<CFileItem>& videoItem) -{ - if (videoItem == nullptr || !videoItem->HasVideoInfoTag()) - return false; - - // update the db - CVideoDatabase videodb; - if (!videodb.Open()) - return false; - - CVideoThumbLoader loader; - CFileItem item(*videoItem); - loader.LoadItem(&item); - - CFileItemList items; - if (item.HasArt("fanart")) - { - CFileItemPtr itemCurrent(new CFileItem("fanart://Current", false)); - itemCurrent->SetArt("thumb", item.GetArt("fanart")); - itemCurrent->SetLabel(g_localizeStrings.Get(20440)); - items.Add(itemCurrent); - } - - // add the none option - { - CFileItemPtr itemNone(new CFileItem("fanart://None", false)); - itemNone->SetArt("icon", videoItem->m_bIsFolder ? "DefaultFolder.png" : "DefaultPicture.png"); - itemNone->SetLabel(g_localizeStrings.Get(20439)); - items.Add(itemNone); - } - - std::string result; - VECSOURCES sources(*CMediaSourceSettings::GetInstance().GetSources("video")); - CServiceBroker::GetMediaManager().GetLocalDrives(sources); - AddItemPathToFileBrowserSources(sources, item); - bool flip = false; - if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || - StringUtils::EqualsNoCase(result, "fanart://Current")) - return false; - - else if (StringUtils::EqualsNoCase(result, "fanart://None") || !CFileUtils::Exists(result)) - result.clear(); - if (!result.empty() && flip) - result = CTextureUtils::GetWrappedImageURL(result, "", "flipped"); - - videodb.SetArtForItem(item.GetVideoInfoTag()->m_iDbId, item.GetVideoInfoTag()->m_type, "fanart", result); - - // clear view cache and reload images - CUtil::DeleteVideoDatabaseDirectoryCache(); - - return true; -} - void CGUIDialogVideoInfo::ShowFor(const CFileItem& item) { auto window = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIWindowVideoNav>(WINDOW_VIDEO_NAV); diff --git a/xbmc/video/dialogs/GUIDialogVideoInfo.h b/xbmc/video/dialogs/GUIDialogVideoInfo.h index ef57ff68c3..06c703cc56 100644 --- a/xbmc/video/dialogs/GUIDialogVideoInfo.h +++ b/xbmc/video/dialogs/GUIDialogVideoInfo.h @@ -55,6 +55,7 @@ public: static bool AddItemsToTag(const std::shared_ptr<CFileItem>& tagItem); static bool RemoveItemsFromTag(const std::shared_ptr<CFileItem>& tagItem); + static bool ChooseAndManageVideoItemArtwork(const std::shared_ptr<CFileItem>& item); static bool ManageVideoItemArtwork(const std::shared_ptr<CFileItem>& item, const MediaType& type); static std::string GetLocalizedVideoType(const std::string &strType); @@ -96,11 +97,6 @@ protected: bool bRemove, CVideoDatabase& database); - /*! \brief Pop up a fanart chooser. Does not utilise remote URLs. - \param videoItem the item to choose fanart for. - */ - static bool OnGetFanart(const std::shared_ptr<CFileItem>& videoItem); - std::shared_ptr<CFileItem> m_movieItem; CFileItemList *m_castList; bool m_bViewReview = false; @@ -113,6 +109,6 @@ protected: private: static std::string ChooseArtType(const CFileItem& item); static bool ManageVideoItemArtwork(const std::shared_ptr<CFileItem>& item, - const MediaType& type, - bool& finished); + const MediaType& mediaType, + const std::string& artType); }; diff --git a/xbmc/video/tags/CMakeLists.txt b/xbmc/video/tags/CMakeLists.txt index ab289f864a..6b23664b36 100644 --- a/xbmc/video/tags/CMakeLists.txt +++ b/xbmc/video/tags/CMakeLists.txt @@ -1,9 +1,11 @@ -set(SOURCES VideoInfoTagLoaderFactory.cpp +set(SOURCES VideoTagExtractionHelper.cpp + VideoInfoTagLoaderFactory.cpp VideoTagLoaderFFmpeg.cpp VideoTagLoaderNFO.cpp VideoTagLoaderPlugin.cpp) set(HEADERS IVideoInfoTagLoader.h + VideoTagExtractionHelper.h VideoInfoTagLoaderFactory.h VideoTagLoaderFFmpeg.h VideoTagLoaderNFO.h diff --git a/xbmc/video/tags/VideoInfoTagLoaderFactory.cpp b/xbmc/video/tags/VideoInfoTagLoaderFactory.cpp index 00ed67a528..6f3c7fa009 100644 --- a/xbmc/video/tags/VideoInfoTagLoaderFactory.cpp +++ b/xbmc/video/tags/VideoInfoTagLoaderFactory.cpp @@ -9,12 +9,10 @@ #include "VideoInfoTagLoaderFactory.h" #include "FileItem.h" -#include "ServiceBroker.h" #include "VideoTagLoaderFFmpeg.h" #include "VideoTagLoaderNFO.h" #include "VideoTagLoaderPlugin.h" -#include "settings/Settings.h" -#include "settings/SettingsComponent.h" +#include "video/tags/VideoTagExtractionHelper.h" using namespace VIDEO; @@ -37,8 +35,7 @@ IVideoInfoTagLoader* CVideoInfoTagLoaderFactory::CreateLoader(const CFileItem& i return nfo; delete nfo; - if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MYVIDEOS_USETAGS) && - (item.IsType(".mkv") || item.IsType(".mp4") || item.IsType(".avi") || item.IsType(".m4v"))) + if (TAGS::CVideoTagExtractionHelper::IsExtractionSupportedFor(item)) { CVideoTagLoaderFFmpeg* ff = new CVideoTagLoaderFFmpeg(item, info, lookInFolder); if (ff->HasInfo()) diff --git a/xbmc/video/tags/VideoTagExtractionHelper.cpp b/xbmc/video/tags/VideoTagExtractionHelper.cpp new file mode 100644 index 0000000000..5ce567aed9 --- /dev/null +++ b/xbmc/video/tags/VideoTagExtractionHelper.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "VideoTagExtractionHelper.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "TextureDatabase.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/URIUtils.h" +#include "video/VideoInfoTag.h" +#include "video/tags/VideoTagLoaderFFmpeg.h" + +using namespace VIDEO::TAGS; + +bool CVideoTagExtractionHelper::IsExtractionSupportedFor(const CFileItem& item) +{ + const std::string fileNameAndPath = item.GetVideoInfoTag()->m_strFileNameAndPath; + return CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_MYVIDEOS_USETAGS) && + URIUtils::HasExtension(fileNameAndPath, ".mkv|.mp4|.avi|.m4v"); +} + +std::string CVideoTagExtractionHelper::ExtractEmbeddedArtFor(const CFileItem& item, + const std::string& artType) +{ + CVideoTagLoaderFFmpeg loader(item, nullptr, false); + CVideoInfoTag tag; + loader.Load(tag, false, nullptr); + for (const auto& it : tag.m_coverArt) + { + if (it.m_type == artType) + { + return CTextureUtils::GetWrappedImageURL(item.GetVideoInfoTag()->m_strFileNameAndPath, + "video_" + artType); + } + } + return {}; +} diff --git a/xbmc/video/tags/VideoTagExtractionHelper.h b/xbmc/video/tags/VideoTagExtractionHelper.h new file mode 100644 index 0000000000..1e6823e1cf --- /dev/null +++ b/xbmc/video/tags/VideoTagExtractionHelper.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include <string> + +class CFileItem; + +namespace VIDEO +{ +namespace TAGS +{ +class CVideoTagExtractionHelper +{ +public: + /*! + \brief Check whether tag extraction is supported for the given item. This is no + check whether the video denoted by the item actually contains any tags. There is also a Kodi + setting for enabling video tag support that is taken into consideration by the implementation of + this function. + \param item [in] the item denoting a video file. + \return True if tag support is enabled and extraction is supported for the given file type. + */ + static bool IsExtractionSupportedFor(const CFileItem& item); + + /*! + \brief Try to extract embedded art of given type from the given item denoting a video file. + \param item [in] the item. + \param artType The type of the art to extract (e.g. "fanart"). + \return The image URL of the embedded art if extraction was successful, false otherwise. + */ + static std::string ExtractEmbeddedArtFor(const CFileItem& item, const std::string& artType); +}; +} // namespace TAGS +} // namespace VIDEO |