aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Morten Kvarving <spiff@kodi.tv>2024-06-25 07:14:40 +0200
committerArne Morten Kvarving <spiff@kodi.tv>2024-07-13 19:18:37 +0200
commitfb529f9b93b9bafd729a19d3f1a1445019447384 (patch)
treeaf2a6a7426b3515a516b07770f7d132cbc3b9e42
parent20fcebda08ce8a4510c96e960ecdf8e0cc54a153 (diff)
changed: move CFileItem::GetLocalFanart to ArtUtils
-rw-r--r--xbmc/FileItem.cpp78
-rw-r--r--xbmc/FileItem.h7
-rw-r--r--xbmc/utils/ArtUtils.cpp97
-rw-r--r--xbmc/utils/ArtUtils.h7
-rw-r--r--xbmc/utils/test/TestArtUtils.cpp107
-rw-r--r--xbmc/video/VideoItemArtworkHandler.cpp3
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<std::string> 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<std::string>::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
@@ -389,13 +389,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.
`useFolder` is set to false
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<std::string> 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.
// <filename>.ext -> <filename>.tbn
// <foldername>/ -> <foldername>.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 <array>
#include <fstream>
+#include <random>
#include <fmt/format.h>
#include <gtest/gtest.h>
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<FanartTest>, 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<TbnTest>, 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<std::string> 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)