2 * Copyright (C) 2005-2023 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "VideoItemArtworkHandler.h"
12 #include "FileItemList.h"
13 #include "MediaSource.h"
14 #include "ServiceBroker.h"
15 #include "filesystem/Directory.h"
16 #include "guilib/LocalizeStrings.h"
17 #include "imagefiles/ImageFileURL.h"
18 #include "music/MusicDatabase.h"
19 #include "settings/Settings.h"
20 #include "settings/SettingsComponent.h"
21 #include "utils/ArtUtils.h"
22 #include "utils/FileExtensionProvider.h"
23 #include "utils/FileUtils.h"
24 #include "utils/URIUtils.h"
25 #include "utils/Variant.h"
26 #include "utils/log.h"
27 #include "video/VideoDatabase.h"
28 #include "video/VideoFileItemClassify.h"
29 #include "video/VideoInfoScanner.h"
30 #include "video/VideoInfoTag.h"
31 #include "video/VideoThumbLoader.h"
32 #include "video/tags/VideoTagExtractionHelper.h"
34 using namespace XFILE
;
41 //-------------------------------------------------------------------------------------------------
42 // CVideoItemArtworkHandler (Generic handler)
43 //-------------------------------------------------------------------------------------------------
45 class CVideoItemArtworkHandler
: public IVideoItemArtworkHandler
48 explicit CVideoItemArtworkHandler(const std::shared_ptr
<CFileItem
>& item
,
49 const std::string
& artType
)
50 : m_item(item
), m_artType(artType
)
54 std::string
GetCurrentArt() const override
;
55 std::string
GetEmbeddedArt() const override
;
56 std::vector
<std::string
> GetRemoteArt() const override
;
57 std::string
GetLocalArt() const override
;
59 std::string
GetDefaultIcon() const override
;
61 void AddItemPathToFileBrowserSources(std::vector
<CMediaSource
>& sources
) override
;
63 void PersistArt(const std::string
& art
) override
;
66 void AddItemPathStringToFileBrowserSources(std::vector
<CMediaSource
>& sources
,
67 const std::string
& itemDir
,
68 const std::string
& label
);
70 const std::shared_ptr
<CFileItem
> m_item
;
71 const std::string m_artType
;
74 std::string
CVideoItemArtworkHandler::GetCurrentArt() const
76 if (m_artType
.empty())
78 CLog::LogF(LOGERROR
, "Art type not set!");
82 std::string currentArt
;
83 if (m_item
->HasArt(m_artType
))
84 currentArt
= m_item
->GetArt(m_artType
);
85 else if (m_item
->HasArt("thumb") && (m_artType
== "poster" || m_artType
== "banner"))
86 currentArt
= m_item
->GetArt("thumb");
91 std::string
CVideoItemArtworkHandler::GetEmbeddedArt() const
93 if (TAGS::CVideoTagExtractionHelper::IsExtractionSupportedFor(*m_item
))
94 return TAGS::CVideoTagExtractionHelper::ExtractEmbeddedArtFor(*m_item
, m_artType
);
99 std::vector
<std::string
> CVideoItemArtworkHandler::GetRemoteArt() const
101 std::vector
<std::string
> remoteArt
;
102 CVideoInfoTag
tag(*m_item
->GetVideoInfoTag());
103 tag
.m_strPictureURL
.Parse();
104 tag
.m_strPictureURL
.GetThumbUrls(remoteArt
, m_artType
);
108 std::string
CVideoItemArtworkHandler::GetLocalArt() const
110 return CVideoThumbLoader::GetLocalArt(*m_item
, m_artType
);
113 std::string
CVideoItemArtworkHandler::GetDefaultIcon() const
115 return m_item
->m_bIsFolder
? "DefaultFolder.png" : "DefaultPicture.png";
118 void CVideoItemArtworkHandler::AddItemPathToFileBrowserSources(std::vector
<CMediaSource
>& sources
)
120 std::string itemDir
= m_item
->GetVideoInfoTag()->m_basePath
;
123 itemDir
= m_item
->GetVideoInfoTag()->GetPath();
125 const CFileItem
itemTmp(itemDir
, false);
126 if (IsVideo(itemTmp
))
127 itemDir
= URIUtils::GetParentPath(itemDir
);
129 AddItemPathStringToFileBrowserSources(sources
, itemDir
,
130 g_localizeStrings
.Get(36041) /* * Item folder */);
133 void CVideoItemArtworkHandler::PersistArt(const std::string
& art
)
135 CVideoDatabase videodb
;
138 CLog::LogF(LOGERROR
, "Cannot open video database!");
142 videodb
.SetArtForItem(m_item
->GetVideoInfoTag()->m_iDbId
, m_item
->GetVideoInfoTag()->m_type
,
145 videodb
.UpdateArtForItem(m_item
->GetVideoInfoTag()->m_iDbId
, m_artType
);
148 void CVideoItemArtworkHandler::AddItemPathStringToFileBrowserSources(
149 std::vector
<CMediaSource
>& sources
, const std::string
& itemDir
, const std::string
& label
)
151 if (!itemDir
.empty() && CDirectory::Exists(itemDir
))
153 CMediaSource itemSource
;
154 itemSource
.strName
= label
;
155 itemSource
.strPath
= itemDir
;
156 sources
.emplace_back(itemSource
);
160 //-------------------------------------------------------------------------------------------------
161 // CVideoItemArtworkArtistHandler (Artist handler)
162 //-------------------------------------------------------------------------------------------------
164 class CVideoItemArtworkArtistHandler
: public CVideoItemArtworkHandler
167 explicit CVideoItemArtworkArtistHandler(const std::shared_ptr
<CFileItem
>& item
,
168 const std::string
& artType
)
169 : CVideoItemArtworkHandler(item
, artType
)
173 std::string
GetCurrentArt() const override
;
174 std::vector
<std::string
> GetRemoteArt() const override
;
175 std::string
GetLocalArt() const override
;
177 std::string
GetDefaultIcon() const override
{ return "DefaultArtist.png"; }
179 void PersistArt(const std::string
& art
) override
;
182 std::string
CVideoItemArtworkArtistHandler::GetCurrentArt() const
184 CMusicDatabase musicdb
;
187 CLog::LogF(LOGERROR
, "Cannot open music database!");
191 std::string currentArt
;
192 const int idArtist
= musicdb
.GetArtistByName(m_item
->GetLabel());
194 currentArt
= musicdb
.GetArtForItem(idArtist
, MediaTypeArtist
, "thumb");
196 if (currentArt
.empty())
198 CVideoDatabase videodb
;
201 CLog::LogF(LOGERROR
, "Cannot open video database!");
205 currentArt
= videodb
.GetArtForItem(m_item
->GetVideoInfoTag()->m_iDbId
,
206 m_item
->GetVideoInfoTag()->m_type
, "thumb");
211 std::vector
<std::string
> CVideoItemArtworkArtistHandler::GetRemoteArt() const
216 std::string
CVideoItemArtworkArtistHandler::GetLocalArt() const
218 CMusicDatabase musicdb
;
221 CLog::LogF(LOGERROR
, "Cannot open music database!");
225 std::string localArt
;
226 const int idArtist
= musicdb
.GetArtistByName(m_item
->GetLabel());
229 // Get artist paths - possible locations for thumb - while music db open
231 musicdb
.GetArtist(idArtist
, artist
);
232 std::string artistPath
;
233 musicdb
.GetArtistPath(artist
, artistPath
); // Artist path in artist info folder
236 bool existsThumb
= false;
238 // First look for artist thumb in the primary location
239 if (!artistPath
.empty())
241 thumb
= URIUtils::AddFileToFolder(artistPath
, "folder.jpg");
242 existsThumb
= CFileUtils::Exists(thumb
);
244 // If not there fall back local to music files (historic location for those album artists with a unique folder)
247 std::string artistOldPath
;
248 musicdb
.GetOldArtistPath(idArtist
, artistOldPath
); // Old artist path, local to music files
249 if (!artistOldPath
.empty())
251 thumb
= URIUtils::AddFileToFolder(artistOldPath
, "folder.jpg");
252 existsThumb
= CFileUtils::Exists(thumb
);
262 void CVideoItemArtworkArtistHandler::PersistArt(const std::string
& art
)
264 CMusicDatabase musicdb
;
267 CLog::LogF(LOGERROR
, "Cannot open music database!");
271 const int idArtist
= musicdb
.GetArtistByName(m_item
->GetLabel());
273 musicdb
.SetArtForItem(idArtist
, MediaTypeArtist
, m_artType
, art
);
276 //-------------------------------------------------------------------------------------------------
277 // CVideoItemArtworkActorHandler (Actor handler)
278 //-------------------------------------------------------------------------------------------------
280 class CVideoItemArtworkActorHandler
: public CVideoItemArtworkHandler
283 explicit CVideoItemArtworkActorHandler(const std::shared_ptr
<CFileItem
>& item
,
284 const std::string
& artType
)
285 : CVideoItemArtworkHandler(item
, artType
)
289 std::string
GetCurrentArt() const override
;
290 std::string
GetLocalArt() const override
;
292 std::string
GetDefaultIcon() const override
{ return "DefaultActor.png"; }
295 std::string
CVideoItemArtworkActorHandler::GetCurrentArt() const
297 CVideoDatabase videodb
;
300 CLog::LogF(LOGERROR
, "Cannot open video database!");
304 return videodb
.GetArtForItem(m_item
->GetVideoInfoTag()->m_iDbId
,
305 m_item
->GetVideoInfoTag()->m_type
, "thumb");
308 std::string
CVideoItemArtworkActorHandler::GetLocalArt() const
310 std::string localArt
;
311 std::string picturePath
;
312 const std::string thumb
= URIUtils::AddFileToFolder(picturePath
, "folder.jpg");
313 if (CFileUtils::Exists(thumb
))
319 //-------------------------------------------------------------------------------------------------
320 // CVideoItemArtworkSeasonHandler (Season handler)
321 //-------------------------------------------------------------------------------------------------
323 class CVideoItemArtworkSeasonHandler
: public CVideoItemArtworkHandler
326 explicit CVideoItemArtworkSeasonHandler(const std::shared_ptr
<CFileItem
>& item
,
327 const std::string
& artType
)
328 : CVideoItemArtworkHandler(item
, artType
)
332 std::vector
<std::string
> GetRemoteArt() const override
;
335 std::vector
<std::string
> CVideoItemArtworkSeasonHandler::GetRemoteArt() const
337 CVideoDatabase videodb
;
340 CLog::LogF(LOGERROR
, "Cannot open video database!");
344 std::vector
<std::string
> remoteArt
;
346 videodb
.GetTvShowInfo("", tag
, m_item
->GetVideoInfoTag()->m_iIdShow
);
347 tag
.m_strPictureURL
.Parse();
348 tag
.m_strPictureURL
.GetThumbUrls(remoteArt
, m_artType
, m_item
->GetVideoInfoTag()->m_iSeason
);
352 //-------------------------------------------------------------------------------------------------
353 // CVideoItemArtworkMovieSetHandler (Movie set handler)
354 //-------------------------------------------------------------------------------------------------
356 class CVideoItemArtworkMovieSetHandler
: public CVideoItemArtworkHandler
359 explicit CVideoItemArtworkMovieSetHandler(const std::shared_ptr
<CFileItem
>& item
,
360 const std::string
& artType
)
361 : CVideoItemArtworkHandler(item
, artType
)
365 std::vector
<std::string
> GetRemoteArt() const override
;
366 std::string
GetLocalArt() const override
;
368 std::string
GetDefaultIcon() const override
{ return "DefaultVideo.png"; }
370 void AddItemPathToFileBrowserSources(std::vector
<CMediaSource
>& sources
) override
;
373 std::vector
<std::string
> CVideoItemArtworkMovieSetHandler::GetRemoteArt() const
375 CVideoDatabase videodb
;
378 CLog::LogF(LOGERROR
, "Cannot open video database!");
382 std::vector
<std::string
> remoteArt
;
383 const std::string baseDir
=
384 StringUtils::Format("videodb://movies/sets/{}", m_item
->GetVideoInfoTag()->m_iDbId
);
386 if (videodb
.GetMoviesNav(baseDir
, items
))
388 for (const auto& item
: items
)
390 CVideoInfoTag
* videotag
= item
->GetVideoInfoTag();
391 videotag
->m_strPictureURL
.Parse();
392 videotag
->m_strPictureURL
.GetThumbUrls(remoteArt
, "set." + m_artType
, -1, true);
398 std::string
CVideoItemArtworkMovieSetHandler::GetLocalArt() const
400 std::string localArt
;
401 const std::string infoFolder
=
402 VIDEO::CVideoInfoScanner::GetMovieSetInfoFolder(m_item
->GetLabel());
403 if (!infoFolder
.empty())
405 CFileItemList availableArtFiles
;
406 CDirectory::GetDirectory(infoFolder
, availableArtFiles
,
407 CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(),
408 DIR_FLAG_NO_FILE_DIRS
| DIR_FLAG_READ_CACHE
| DIR_FLAG_NO_FILE_INFO
);
409 for (const auto& artFile
: availableArtFiles
)
411 std::string candidate
= URIUtils::GetFileName(artFile
->GetDynPath());
412 URIUtils::RemoveExtension(candidate
);
413 if (StringUtils::EqualsNoCase(candidate
, m_artType
))
415 localArt
= artFile
->GetDynPath();
423 void CVideoItemArtworkMovieSetHandler::AddItemPathToFileBrowserSources(
424 std::vector
<CMediaSource
>& sources
)
426 AddItemPathStringToFileBrowserSources(
427 sources
, VIDEO::CVideoInfoScanner::GetMovieSetInfoFolder(m_item
->GetLabel()),
428 g_localizeStrings
.Get(36041) /* * Item folder */);
429 AddItemPathStringToFileBrowserSources(
431 CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(
432 CSettings::SETTING_VIDEOLIBRARY_MOVIESETSFOLDER
),
433 "* " + g_localizeStrings
.Get(20226) /* Movie set information folder */);
436 //-------------------------------------------------------------------------------------------------
437 // CVideoItemArtworkFanartHandler (Handler for all media types, to manage fanart art type)
438 //-------------------------------------------------------------------------------------------------
440 class CVideoItemArtworkFanartHandler
: public CVideoItemArtworkHandler
443 explicit CVideoItemArtworkFanartHandler(const std::shared_ptr
<CFileItem
>& item
,
444 const std::string
& artType
)
445 : CVideoItemArtworkHandler(item
, artType
)
447 // Ensure the fanart is unpacked
448 m_item
->GetVideoInfoTag()->m_fanart
.Unpack();
451 std::string
GetCurrentArt() const override
;
452 std::vector
<std::string
> GetRemoteArt() const override
;
453 std::string
GetLocalArt() const override
;
455 std::string
GetDefaultIcon() const override
{ return "DefaultPicture.png"; }
456 bool SupportsFlippedArt() const override
{ return true; }
458 std::string
UpdateEmbeddedArt(const std::string
& art
) override
;
459 std::string
UpdateRemoteArt(const std::vector
<std::string
>& art
, int index
) override
;
462 std::string
CVideoItemArtworkFanartHandler::GetCurrentArt() const
464 return m_item
->GetArt("fanart");
467 std::vector
<std::string
> CVideoItemArtworkFanartHandler::GetRemoteArt() const
469 std::vector
<std::string
> remoteArt
;
470 const CVideoInfoTag
* videoTag
= m_item
->GetVideoInfoTag();
471 for (unsigned int i
= 0; i
< videoTag
->m_fanart
.GetNumFanarts(); ++i
)
473 const std::string thumb
= videoTag
->m_fanart
.GetPreviewURL(i
);
474 if (URIUtils::IsProtocol(thumb
, "image"))
477 remoteArt
.emplace_back(IMAGE_FILES::URLFromFile(thumb
));
482 std::string
CVideoItemArtworkFanartHandler::GetLocalArt() const
484 return ART::GetLocalFanart(*m_item
);
487 std::string
CVideoItemArtworkFanartHandler::UpdateEmbeddedArt(const std::string
& art
)
489 CVideoDatabase videodb
;
492 CLog::LogF(LOGERROR
, "Cannot open video database!");
496 CVideoInfoTag
* videoTag
= m_item
->GetVideoInfoTag();
497 const int currentTag
= videoTag
->m_fanart
.GetNumFanarts();
498 int matchingTag
= -1;
499 for (int i
= 0; i
< currentTag
; ++i
)
501 if (URIUtils::IsProtocol(videoTag
->m_fanart
.GetImageURL(i
), "image"))
505 if (matchingTag
!= -1)
507 videoTag
->m_fanart
.AddFanart(art
, "", "");
508 matchingTag
= currentTag
;
511 videoTag
->m_fanart
.SetPrimaryFanart(matchingTag
);
512 videodb
.UpdateFanart(*m_item
, m_item
->GetVideoContentType());
516 std::string
CVideoItemArtworkFanartHandler::UpdateRemoteArt(const std::vector
<std::string
>& art
,
519 CVideoInfoTag
* videoTag
= m_item
->GetVideoInfoTag();
521 CVideoDatabase videodb
;
524 CLog::LogF(LOGERROR
, "Cannot open video database!");
528 videoTag
->m_fanart
.SetPrimaryFanart(index
);
529 videodb
.UpdateFanart(*m_item
, m_item
->GetVideoContentType());
531 return videoTag
->m_fanart
.GetImageURL();
534 } // unnamed namespace
536 //-------------------------------------------------------------------------------------------------
537 // IVideoItemArtworkHandlerFactory
538 //-------------------------------------------------------------------------------------------------
540 std::unique_ptr
<IVideoItemArtworkHandler
> IVideoItemArtworkHandlerFactory::Create(
541 const std::shared_ptr
<CFileItem
>& item
,
542 const std::string
& mediaType
,
543 const std::string
& artType
)
545 std::unique_ptr
<IVideoItemArtworkHandler
> artHandler
;
547 if (artType
== "fanart" && mediaType
!= MediaTypeVideoCollection
)
548 artHandler
= std::make_unique
<CVideoItemArtworkFanartHandler
>(item
, artType
);
549 else if (mediaType
== MediaTypeArtist
)
550 artHandler
= std::make_unique
<CVideoItemArtworkArtistHandler
>(item
, artType
);
551 else if (mediaType
== "actor")
552 artHandler
= std::make_unique
<CVideoItemArtworkActorHandler
>(item
, artType
);
553 else if (mediaType
== MediaTypeSeason
)
554 artHandler
= std::make_unique
<CVideoItemArtworkSeasonHandler
>(item
, artType
);
555 else if (mediaType
== MediaTypeVideoCollection
)
556 artHandler
= std::make_unique
<CVideoItemArtworkMovieSetHandler
>(item
, artType
);
558 artHandler
= std::make_unique
<CVideoItemArtworkHandler
>(item
, artType
);
563 } // namespace KODI::VIDEO