From fb529f9b93b9bafd729a19d3f1a1445019447384 Mon Sep 17 00:00:00 2001 From: Arne Morten Kvarving Date: Tue, 25 Jun 2024 07:14:40 +0200 Subject: changed: move CFileItem::GetLocalFanart to ArtUtils --- xbmc/FileItem.cpp | 78 ------------------------ xbmc/FileItem.h | 7 --- xbmc/utils/ArtUtils.cpp | 97 ++++++++++++++++++++++++++++++ xbmc/utils/ArtUtils.h | 7 +++ xbmc/utils/test/TestArtUtils.cpp | 107 +++++++++++++++++++++++++++++++++ xbmc/video/VideoItemArtworkHandler.cpp | 3 +- 6 files changed, 213 insertions(+), 86 deletions(-) diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp index 2776627018..21e5dfd9d3 100644 --- a/xbmc/FileItem.cpp +++ b/xbmc/FileItem.cpp @@ -2196,84 +2196,6 @@ std::string CFileItem::GetBaseMoviePath(bool bUseFolderNames) const return strMovieName; } -std::string CFileItem::GetLocalFanart() const -{ - if (VIDEO::IsVideoDb(*this)) - { - if (!HasVideoInfoTag()) - return ""; // nothing can be done - CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder); - return dbItem.GetLocalFanart(); - } - - std::string strFile2; - std::string strFile = m_strPath; - if (IsStack()) - { - std::string strPath; - URIUtils::GetParentPath(m_strPath,strPath); - CStackDirectory dir; - std::string strPath2; - strPath2 = dir.GetStackedTitlePath(strFile); - strFile = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strPath2)); - CFileItem item(dir.GetFirstStackedFile(m_strPath),false); - std::string strTBNFile(URIUtils::ReplaceExtension(ART::GetTBNFile(item), "-fanart")); - strFile2 = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strTBNFile)); - } - if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile)) - { - std::string strPath = URIUtils::GetDirectory(strFile); - std::string strParent; - URIUtils::GetParentPath(strPath,strParent); - strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(m_strPath)); - } - - // no local fanart available for these - if (NETWORK::IsInternetStream(*this) || URIUtils::IsUPnP(strFile) || - URIUtils::IsBluray(strFile) || IsLiveTV() || IsPlugin() || IsAddonsPath() || IsDVD() || - (URIUtils::IsFTP(strFile) && - !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs) || - m_strPath.empty()) - return ""; - - std::string strDir = URIUtils::GetDirectory(strFile); - - if (strDir.empty()) - return ""; - - CFileItemList items; - CDirectory::GetDirectory(strDir, items, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); - if (IsOpticalMediaFile()) - { // grab from the optical media parent folder as well - CFileItemList moreItems; - CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); - items.Append(moreItems); - } - - std::vector fanarts = { "fanart" }; - - strFile = URIUtils::ReplaceExtension(strFile, "-fanart"); - fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile)); - - if (!strFile2.empty()) - fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile2)); - - for (std::vector::const_iterator i = fanarts.begin(); i != fanarts.end(); ++i) - { - for (int j = 0; j < items.Size(); j++) - { - std::string strCandidate = URIUtils::GetFileName(items[j]->m_strPath); - URIUtils::RemoveExtension(strCandidate); - std::string strFanart = *i; - URIUtils::RemoveExtension(strFanart); - if (StringUtils::EqualsNoCase(strCandidate, strFanart)) - return items[j]->m_strPath; - } - } - - return ""; -} - std::string CFileItem::GetLocalMetadataPath() const { if (m_bIsFolder && !IsFileFolder()) diff --git a/xbmc/FileItem.h b/xbmc/FileItem.h index 140d130f48..a6ffd48cec 100644 --- a/xbmc/FileItem.h +++ b/xbmc/FileItem.h @@ -388,13 +388,6 @@ public: CPictureInfoTag* GetPictureInfoTag(); - /*! - \brief Get the local fanart for this item if it exists - \return path to the local fanart for this item, or empty if none exists - \sa GetFolderThumb, GetTBNFile - */ - std::string GetLocalFanart() const; - /*! \brief Assemble the base filename of local artwork for an item, accounting for archives, stacks and multi-paths, and BDMV/VIDEO_TS folders. diff --git a/xbmc/utils/ArtUtils.cpp b/xbmc/utils/ArtUtils.cpp index c76192956e..a3e98c1c89 100644 --- a/xbmc/utils/ArtUtils.cpp +++ b/xbmc/utils/ArtUtils.cpp @@ -9,15 +9,112 @@ #include "ArtUtils.h" #include "FileItem.h" +#include "FileItemList.h" +#include "ServiceBroker.h" +#include "filesystem/Directory.h" #include "filesystem/File.h" #include "filesystem/StackDirectory.h" +#include "network/NetworkFileItemClassify.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" +#include "utils/FileExtensionProvider.h" +#include "utils/StringUtils.h" #include "utils/URIUtils.h" +#include "video/VideoFileItemClassify.h" +#include "video/VideoInfoTag.h" using namespace XFILE; namespace KODI::ART { +std::string GetLocalFanart(const CFileItem& item) +{ + if (VIDEO::IsVideoDb(item)) + { + if (!item.HasVideoInfoTag()) + return ""; // nothing can be done + CFileItem dbItem(item.m_bIsFolder ? item.GetVideoInfoTag()->m_strPath + : item.GetVideoInfoTag()->m_strFileNameAndPath, + item.m_bIsFolder); + return GetLocalFanart(dbItem); + } + + std::string strFile2; + std::string strFile = item.GetPath(); + if (item.IsStack()) + { + std::string strPath; + URIUtils::GetParentPath(item.GetPath(), strPath); + CStackDirectory dir; + std::string strPath2; + strPath2 = dir.GetStackedTitlePath(strFile); + strFile = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strPath2)); + CFileItem fan_item(dir.GetFirstStackedFile(item.GetPath()), false); + std::string strTBNFile(URIUtils::ReplaceExtension(GetTBNFile(fan_item), "-fanart")); + strFile2 = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strTBNFile)); + } + + if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile)) + { + std::string strPath = URIUtils::GetDirectory(strFile); + std::string strParent; + URIUtils::GetParentPath(strPath, strParent); + strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(item.GetPath())); + } + + // no local fanart available for these + if (NETWORK::IsInternetStream(item) || URIUtils::IsUPnP(strFile) || URIUtils::IsBluray(strFile) || + item.IsLiveTV() || item.IsPlugin() || item.IsAddonsPath() || item.IsDVD() || + (URIUtils::IsFTP(strFile) && + !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs) || + item.GetPath().empty()) + return ""; + + std::string strDir = URIUtils::GetDirectory(strFile); + + if (strDir.empty()) + return ""; + + CFileItemList items; + CDirectory::GetDirectory(strDir, items, + CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), + DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); + if (item.IsOpticalMediaFile()) + { // grab from the optical media parent folder as well + CFileItemList moreItems; + CDirectory::GetDirectory(item.GetLocalMetadataPath(), moreItems, + CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), + DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO); + items.Append(moreItems); + } + + std::vector fanarts = {"fanart"}; + + strFile = URIUtils::ReplaceExtension(strFile, "-fanart"); + fanarts.insert(item.m_bIsFolder ? fanarts.end() : fanarts.begin(), + URIUtils::GetFileName(strFile)); + + if (!strFile2.empty()) + fanarts.insert(item.m_bIsFolder ? fanarts.end() : fanarts.begin(), + URIUtils::GetFileName(strFile2)); + + for (const auto& fanart : fanarts) + { + for (const auto& item : items) + { + std::string strCandidate = URIUtils::GetFileName(item->GetPath()); + URIUtils::RemoveExtension(strCandidate); + std::string strFanart = fanart; + URIUtils::RemoveExtension(strFanart); + if (StringUtils::EqualsNoCase(strCandidate, strFanart)) + return item->GetPath(); + } + } + + return ""; +} + // Gets the .tbn filename from a file or folder name. // .ext -> .tbn // / -> .tbn diff --git a/xbmc/utils/ArtUtils.h b/xbmc/utils/ArtUtils.h index b2ae688206..564b42b056 100644 --- a/xbmc/utils/ArtUtils.h +++ b/xbmc/utils/ArtUtils.h @@ -15,6 +15,13 @@ class CFileItem; namespace KODI::ART { +/*! + \brief Get the local fanart for item if it exists + \return path to the local fanart for this item, or empty if none exists + \sa GetFolderThumb, GetTBNFile + */ +std::string GetLocalFanart(const CFileItem& item); + // Gets the .tbn file associated with an item std::string GetTBNFile(const CFileItem& item); diff --git a/xbmc/utils/test/TestArtUtils.cpp b/xbmc/utils/test/TestArtUtils.cpp index 92770435ec..324836b233 100644 --- a/xbmc/utils/test/TestArtUtils.cpp +++ b/xbmc/utils/test/TestArtUtils.cpp @@ -7,19 +7,75 @@ */ #include "FileItem.h" +#include "URL.h" +#include "filesystem/Directory.h" #include "platform/Filesystem.h" #include "utils/ArtUtils.h" #include "utils/FileUtils.h" +#include "utils/StringUtils.h" #include "utils/URIUtils.h" +#include "video/VideoInfoTag.h" #include #include +#include #include #include using namespace KODI; +namespace +{ + +std::string unique_path(const std::string& input) +{ + std::random_device rd; + std::mt19937 gen(rd()); + auto randchar = [&gen]() + { + const std::string set = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + std::uniform_int_distribution<> select(0, set.size() - 1); + return set[select(gen)]; + }; + + std::string ret; + ret.reserve(input.size()); + std::transform(input.begin(), input.end(), std::back_inserter(ret), + [&randchar](const char c) { return (c == '%') ? randchar() : c; }); + + return ret; +} + +struct FanartTest +{ + std::string path; + std::string result; +}; + +class GetLocalFanartTest : public testing::WithParamInterface, public testing::Test +{ +}; + +const auto local_fanart_tests = std::array{ + FanartTest{"stack://#DIRECTORY#foo-cd1.avi , #DIRECTORY#foo-cd2.avi", "foo-fanart.jpg"}, + FanartTest{"stack://#DIRECTORY#foo-cd1.avi , #DIRECTORY#foo-cd2.avi", "foo-cd1-fanart.jpg"}, + FanartTest{"zip://#URLENCODED_DIRECTORY#bar.zip/foo.avi", "foo-fanart.jpg"}, + FanartTest{"ftp://some.where/foo.avi", ""}, + FanartTest{"https://some.where/foo.avi", ""}, + FanartTest{"upnp://some.where/123", ""}, + FanartTest{"bluray://1", ""}, + FanartTest{"/home/user/1.pvr", ""}, + FanartTest{"plugin://random.video/1", ""}, + FanartTest{"addons://plugins/video/1", ""}, + FanartTest{"dvd://1", ""}, + FanartTest{"", ""}, + FanartTest{"foo.avi", ""}, + FanartTest{"foo.avi", "foo-fanart.jpg"}, + FanartTest{"videodb://movies/1", ""}, + FanartTest{"videodb://movies/1", "foo-fanart.jpg"}, +}; + struct TbnTest { std::string path; @@ -31,6 +87,57 @@ class GetTbnTest : public testing::WithParamInterface, public testing:: { }; +} // namespace + +TEST_P(GetLocalFanartTest, GetLocalFanart) +{ + std::string path, file_path, uniq; + if (GetParam().result.empty()) + file_path = GetParam().path; + else + { + std::error_code ec; + auto tmpdir = KODI::PLATFORM::FILESYSTEM::temp_directory_path(ec); + ASSERT_TRUE(!ec); + uniq = unique_path("FanartTest%%%%%"); + path = URIUtils::AddFileToFolder(tmpdir, uniq); + URIUtils::AddSlashAtEnd(path); + XFILE::CDirectory::Create(path); + std::ofstream of(URIUtils::AddFileToFolder(path, GetParam().result), std::ios::out); + if (GetParam().path.find("#DIRECTORY#") != std::string::npos) + { + file_path = GetParam().path; + StringUtils::Replace(file_path, "#DIRECTORY#", path); + } + else if (GetParam().path.find("#URLENCODED_DIRECTORY#") != std::string::npos) + { + file_path = GetParam().path; + StringUtils::Replace(file_path, "#URLENCODED_DIRECTORY#", CURL::Encode(path)); + } + else if (GetParam().path.starts_with("videodb://")) + { + file_path = GetParam().path; + } + else + file_path = + URIUtils::AddFileToFolder(URIUtils::AddFileToFolder(tmpdir, uniq), GetParam().path); + } + + CFileItem item(file_path, false); + if (GetParam().path.starts_with("videodb://") && !GetParam().result.empty()) + { + item.GetVideoInfoTag()->m_strFileNameAndPath = URIUtils::AddFileToFolder(path, "foo.avi"); + } + const std::string res = ART::GetLocalFanart(item); + + EXPECT_EQ(URIUtils::GetFileName(res), GetParam().result); + + if (!GetParam().result.empty()) + XFILE::CDirectory::RemoveRecursive(path); +} + +INSTANTIATE_TEST_SUITE_P(TestArtUtils, GetLocalFanartTest, testing::ValuesIn(local_fanart_tests)); + TEST_P(GetTbnTest, TbnTest) { EXPECT_EQ(ART::GetTBNFile(CFileItem(GetParam().path, GetParam().isFolder)), GetParam().result); diff --git a/xbmc/video/VideoItemArtworkHandler.cpp b/xbmc/video/VideoItemArtworkHandler.cpp index 847267c1c9..aee0401075 100644 --- a/xbmc/video/VideoItemArtworkHandler.cpp +++ b/xbmc/video/VideoItemArtworkHandler.cpp @@ -18,6 +18,7 @@ #include "music/MusicDatabase.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" +#include "utils/ArtUtils.h" #include "utils/FileExtensionProvider.h" #include "utils/FileUtils.h" #include "utils/URIUtils.h" @@ -478,7 +479,7 @@ std::vector CVideoItemArtworkFanartHandler::GetRemoteArt() const std::string CVideoItemArtworkFanartHandler::GetLocalArt() const { - return m_item->GetLocalFanart(); + return ART::GetLocalFanart(*m_item); } std::string CVideoItemArtworkFanartHandler::UpdateEmbeddedArt(const std::string& art) -- cgit v1.2.3