[videodb] Remove nested transaction when saving state after stopping PVR playback
[xbmc.git] / xbmc / video / VideoItemArtworkHandler.cpp
blob28fa95e50497616fbbdc0db8c7b2f7ef1a84cdd5
1 /*
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.
7 */
9 #include "VideoItemArtworkHandler.h"
11 #include "FileItem.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;
36 namespace KODI::VIDEO
39 namespace
41 //-------------------------------------------------------------------------------------------------
42 // CVideoItemArtworkHandler (Generic handler)
43 //-------------------------------------------------------------------------------------------------
45 class CVideoItemArtworkHandler : public IVideoItemArtworkHandler
47 public:
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;
65 protected:
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!");
79 return {};
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");
88 return currentArt;
91 std::string CVideoItemArtworkHandler::GetEmbeddedArt() const
93 if (TAGS::CVideoTagExtractionHelper::IsExtractionSupportedFor(*m_item))
94 return TAGS::CVideoTagExtractionHelper::ExtractEmbeddedArtFor(*m_item, m_artType);
96 return {};
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);
105 return remoteArt;
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;
121 //season
122 if (itemDir.empty())
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;
136 if (!videodb.Open())
138 CLog::LogF(LOGERROR, "Cannot open video database!");
139 return;
142 videodb.SetArtForItem(m_item->GetVideoInfoTag()->m_iDbId, m_item->GetVideoInfoTag()->m_type,
143 m_artType, art);
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
166 public:
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;
185 if (!musicdb.Open())
187 CLog::LogF(LOGERROR, "Cannot open music database!");
188 return {};
191 std::string currentArt;
192 const int idArtist = musicdb.GetArtistByName(m_item->GetLabel());
193 if (idArtist >= 0)
194 currentArt = musicdb.GetArtForItem(idArtist, MediaTypeArtist, "thumb");
196 if (currentArt.empty())
198 CVideoDatabase videodb;
199 if (!videodb.Open())
201 CLog::LogF(LOGERROR, "Cannot open video database!");
202 return {};
205 currentArt = videodb.GetArtForItem(m_item->GetVideoInfoTag()->m_iDbId,
206 m_item->GetVideoInfoTag()->m_type, "thumb");
208 return currentArt;
211 std::vector<std::string> CVideoItemArtworkArtistHandler::GetRemoteArt() const
213 return {};
216 std::string CVideoItemArtworkArtistHandler::GetLocalArt() const
218 CMusicDatabase musicdb;
219 if (!musicdb.Open())
221 CLog::LogF(LOGERROR, "Cannot open music database!");
222 return {};
225 std::string localArt;
226 const int idArtist = musicdb.GetArtistByName(m_item->GetLabel());
227 if (idArtist >= 0)
229 // Get artist paths - possible locations for thumb - while music db open
230 CArtist artist;
231 musicdb.GetArtist(idArtist, artist);
232 std::string artistPath;
233 musicdb.GetArtistPath(artist, artistPath); // Artist path in artist info folder
235 std::string thumb;
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)
245 if (!existsThumb)
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);
256 if (existsThumb)
257 localArt = thumb;
259 return localArt;
262 void CVideoItemArtworkArtistHandler::PersistArt(const std::string& art)
264 CMusicDatabase musicdb;
265 if (!musicdb.Open())
267 CLog::LogF(LOGERROR, "Cannot open music database!");
268 return;
271 const int idArtist = musicdb.GetArtistByName(m_item->GetLabel());
272 if (idArtist >= 0)
273 musicdb.SetArtForItem(idArtist, MediaTypeArtist, m_artType, art);
276 //-------------------------------------------------------------------------------------------------
277 // CVideoItemArtworkActorHandler (Actor handler)
278 //-------------------------------------------------------------------------------------------------
280 class CVideoItemArtworkActorHandler : public CVideoItemArtworkHandler
282 public:
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;
298 if (!videodb.Open())
300 CLog::LogF(LOGERROR, "Cannot open video database!");
301 return {};
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))
314 localArt = thumb;
316 return localArt;
319 //-------------------------------------------------------------------------------------------------
320 // CVideoItemArtworkSeasonHandler (Season handler)
321 //-------------------------------------------------------------------------------------------------
323 class CVideoItemArtworkSeasonHandler : public CVideoItemArtworkHandler
325 public:
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;
338 if (!videodb.Open())
340 CLog::LogF(LOGERROR, "Cannot open video database!");
341 return {};
344 std::vector<std::string> remoteArt;
345 CVideoInfoTag tag;
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);
349 return remoteArt;
352 //-------------------------------------------------------------------------------------------------
353 // CVideoItemArtworkMovieSetHandler (Movie set handler)
354 //-------------------------------------------------------------------------------------------------
356 class CVideoItemArtworkMovieSetHandler : public CVideoItemArtworkHandler
358 public:
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;
376 if (!videodb.Open())
378 CLog::LogF(LOGERROR, "Cannot open video database!");
379 return {};
382 std::vector<std::string> remoteArt;
383 const std::string baseDir =
384 StringUtils::Format("videodb://movies/sets/{}", m_item->GetVideoInfoTag()->m_iDbId);
385 CFileItemList items;
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);
395 return remoteArt;
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();
416 break;
420 return localArt;
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(
430 sources,
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
442 public:
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"))
475 continue;
477 remoteArt.emplace_back(IMAGE_FILES::URLFromFile(thumb));
479 return remoteArt;
482 std::string CVideoItemArtworkFanartHandler::GetLocalArt() const
484 return ART::GetLocalFanart(*m_item);
487 std::string CVideoItemArtworkFanartHandler::UpdateEmbeddedArt(const std::string& art)
489 CVideoDatabase videodb;
490 if (!videodb.Open())
492 CLog::LogF(LOGERROR, "Cannot open video database!");
493 return art;
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"))
502 matchingTag = i;
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());
513 return art;
516 std::string CVideoItemArtworkFanartHandler::UpdateRemoteArt(const std::vector<std::string>& art,
517 int index)
519 CVideoInfoTag* videoTag = m_item->GetVideoInfoTag();
521 CVideoDatabase videodb;
522 if (!videodb.Open())
524 CLog::LogF(LOGERROR, "Cannot open video database!");
526 else
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);
557 else
558 artHandler = std::make_unique<CVideoItemArtworkHandler>(item, artType);
560 return artHandler;
563 } // namespace KODI::VIDEO