aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Sommerfeld <3226626+ksooo@users.noreply.github.com>2023-09-11 08:08:10 +0200
committerGitHub <noreply@github.com>2023-09-11 08:08:10 +0200
commit085a40300fa8c0d20e9591ea224241b9c5a8eee5 (patch)
treebb6c57ae4a87cc09aa9667fef97ed96938407de9
parent327fd819622980f578ebe1a40b9f0520d933712f (diff)
parent7fe525bacadf704dae1d12c42b63760fe2d403d1 (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.po7
-rw-r--r--xbmc/video/CMakeLists.txt2
-rw-r--r--xbmc/video/VideoItemArtworkHandler.cpp554
-rw-r--r--xbmc/video/VideoItemArtworkHandler.h53
-rw-r--r--xbmc/video/dialogs/GUIDialogVideoInfo.cpp589
-rw-r--r--xbmc/video/dialogs/GUIDialogVideoInfo.h10
-rw-r--r--xbmc/video/tags/CMakeLists.txt4
-rw-r--r--xbmc/video/tags/VideoInfoTagLoaderFactory.cpp7
-rw-r--r--xbmc/video/tags/VideoTagExtractionHelper.cpp45
-rw-r--r--xbmc/video/tags/VideoTagExtractionHelper.h41
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