2 * Copyright (C) 2005-2018 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 "VideoThumbLoader.h"
12 #include "FileItemList.h"
13 #include "ServiceBroker.h"
14 #include "TextureCache.h"
16 #include "cores/VideoPlayer/DVDFileInfo.h"
17 #include "cores/VideoSettings.h"
18 #include "filesystem/Directory.h"
19 #include "filesystem/File.h"
20 #include "filesystem/StackDirectory.h"
21 #include "guilib/GUIComponent.h"
22 #include "guilib/StereoscopicsManager.h"
23 #include "imagefiles/ImageFileURL.h"
24 #include "music/MusicDatabase.h"
25 #include "music/tags/MusicInfoTag.h"
26 #include "network/NetworkFileItemClassify.h"
27 #include "settings/AdvancedSettings.h"
28 #include "settings/SettingUtils.h"
29 #include "settings/Settings.h"
30 #include "settings/SettingsComponent.h"
31 #include "utils/StringUtils.h"
32 #include "utils/URIUtils.h"
33 #include "utils/log.h"
34 #include "video/VideoDatabase.h"
35 #include "video/VideoFileItemClassify.h"
36 #include "video/VideoInfoTag.h"
37 #include "video/VideoManagerTypes.h"
38 #include "video/guilib/VideoVersionHelper.h"
45 using namespace XFILE
;
47 CVideoThumbLoader::CVideoThumbLoader() : CThumbLoader()
49 m_videoDatabase
= new CVideoDatabase();
52 CVideoThumbLoader::~CVideoThumbLoader()
55 delete m_videoDatabase
;
58 void CVideoThumbLoader::OnLoaderStart()
60 m_videoDatabase
->Open();
62 CThumbLoader::OnLoaderStart();
65 void CVideoThumbLoader::OnLoaderFinish()
67 m_videoDatabase
->Close();
69 CThumbLoader::OnLoaderFinish();
74 std::vector
<std::string
> GetSettingListAsString(const std::string
& settingID
)
76 std::vector
<CVariant
> values
=
77 CServiceBroker::GetSettingsComponent()->GetSettings()->GetList(settingID
);
78 std::vector
<std::string
> result
;
79 std::transform(values
.begin(), values
.end(), std::back_inserter(result
),
80 [](const CVariant
& s
) { return s
.asString(); });
84 const std::map
<std::string
, std::vector
<std::string
>> artTypeDefaults
= {
85 {MediaTypeEpisode
, {"thumb"}},
86 {MediaTypeTvShow
, {"poster", "fanart", "banner"}},
87 {MediaTypeSeason
, {"poster", "fanart", "banner"}},
88 {MediaTypeMovie
, {"poster", "fanart"}},
89 {MediaTypeVideoCollection
, {"poster", "fanart"}},
90 {MediaTypeMusicVideo
, {"poster", "fanart"}},
91 {MediaTypeVideoVersion
, {"poster", "fanart", "banner", "thumb"}},
92 {MediaTypeNone
, {"poster", "fanart", "banner", "thumb"}},
95 const std::vector
<std::string
> artTypeDefaultsFallback
= {};
97 const std::vector
<std::string
>& GetArtTypeDefault(const std::string
& mediaType
)
99 auto defaults
= artTypeDefaults
.find(mediaType
);
100 if (defaults
!= artTypeDefaults
.end())
101 return defaults
->second
;
102 return artTypeDefaultsFallback
;
105 const std::map
<std::string
, std::string
> artTypeSettings
= {
106 {MediaTypeEpisode
, CSettings::SETTING_VIDEOLIBRARY_EPISODEART_WHITELIST
},
107 {MediaTypeTvShow
, CSettings::SETTING_VIDEOLIBRARY_TVSHOWART_WHITELIST
},
108 {MediaTypeSeason
, CSettings::SETTING_VIDEOLIBRARY_TVSHOWART_WHITELIST
},
109 {MediaTypeMovie
, CSettings::SETTING_VIDEOLIBRARY_MOVIEART_WHITELIST
},
110 {MediaTypeVideoCollection
, CSettings::SETTING_VIDEOLIBRARY_MOVIEART_WHITELIST
},
111 {MediaTypeMusicVideo
, CSettings::SETTING_VIDEOLIBRARY_MUSICVIDEOART_WHITELIST
},
112 {MediaTypeVideoVersion
, CSettings::SETTING_VIDEOLIBRARY_MOVIEART_WHITELIST
},
116 std::vector
<std::string
> CVideoThumbLoader::GetArtTypes(const std::string
&type
)
118 int artworkLevel
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
119 CSettings::SETTING_VIDEOLIBRARY_ARTWORK_LEVEL
);
120 if (artworkLevel
== CSettings::VIDEOLIBRARY_ARTWORK_LEVEL_NONE
)
125 std::vector
<std::string
> result
= GetArtTypeDefault(type
);
126 if (artworkLevel
!= CSettings::VIDEOLIBRARY_ARTWORK_LEVEL_CUSTOM
)
131 auto settings
= artTypeSettings
.find(type
);
132 if (settings
== artTypeSettings
.end())
135 for (auto& artType
: GetSettingListAsString(settings
->second
))
137 if (find(result
.begin(), result
.end(), artType
) == result
.end())
138 result
.push_back(artType
);
144 bool CVideoThumbLoader::IsValidArtType(const std::string
& potentialArtType
)
146 return !potentialArtType
.empty() && potentialArtType
.length() <= 25 &&
148 potentialArtType
.begin(), potentialArtType
.end(),
149 StringUtils::isasciialphanum
150 ) == potentialArtType
.end();
153 bool CVideoThumbLoader::IsArtTypeInWhitelist(const std::string
& artType
, const std::vector
<std::string
>& whitelist
, bool exact
)
155 // whitelist contains art "families", 'fanart' also matches 'fanart1', 'fanart2', and so on
156 std::string compareArtType
= artType
;
158 StringUtils::TrimRight(compareArtType
, "0123456789");
160 return std::find(whitelist
.begin(), whitelist
.end(), compareArtType
) != whitelist
.end();
164 * Look for a thumbnail for pItem. If one does not exist, look for an autogenerated
165 * thumbnail. If that does not exist, attempt to autogenerate one. Finally, check
166 * for the existence of fanart and set properties accordingly.
167 * @return: true if pItem has been modified
169 bool CVideoThumbLoader::LoadItem(CFileItem
* pItem
)
171 bool result
= LoadItemCached(pItem
);
172 result
|= LoadItemLookup(pItem
);
177 bool CVideoThumbLoader::LoadItemCached(CFileItem
* pItem
)
179 if (pItem
->m_bIsShareOrDrive
180 || pItem
->IsParentFolder())
183 m_videoDatabase
->Open();
185 if (!pItem
->HasVideoInfoTag() || !pItem
->GetVideoInfoTag()->HasStreamDetails()) // no stream details
187 if ((pItem
->HasVideoInfoTag() &&
188 pItem
->GetVideoInfoTag()->m_iFileId
>= 0) // file (or maybe folder) is in the database
189 || (!pItem
->m_bIsFolder
&&
191 *pItem
))) // Some other video file for which we haven't yet got any database details
193 if (m_videoDatabase
->GetStreamDetails(*pItem
))
198 // video db items normally have info in the database
199 if (pItem
->HasVideoInfoTag() && !pItem
->GetProperty("libraryartfilled").asBoolean())
201 FillLibraryArt(*pItem
);
203 if (!pItem
->GetVideoInfoTag()->m_type
.empty() &&
204 pItem
->GetVideoInfoTag()->m_type
!= MediaTypeMovie
&&
205 pItem
->GetVideoInfoTag()->m_type
!= MediaTypeTvShow
&&
206 pItem
->GetVideoInfoTag()->m_type
!= MediaTypeEpisode
&&
207 pItem
->GetVideoInfoTag()->m_type
!= MediaTypeMusicVideo
&&
208 pItem
->GetVideoInfoTag()->m_type
!= MediaTypeVideoVersion
)
210 m_videoDatabase
->Close();
211 return true; // nothing else to be done
215 // if we have no art, look for it all
216 std::map
<std::string
, std::string
> artwork
= pItem
->GetArt();
219 std::vector
<std::string
> artTypes
= GetArtTypes(pItem
->HasVideoInfoTag() ? pItem
->GetVideoInfoTag()->m_type
: "");
220 if (find(artTypes
.begin(), artTypes
.end(), "thumb") == artTypes
.end())
221 artTypes
.emplace_back("thumb"); // always look for "thumb" art for files
222 for (std::vector
<std::string
>::const_iterator i
= artTypes
.begin(); i
!= artTypes
.end(); ++i
)
224 std::string type
= *i
;
225 std::string art
= GetCachedImage(*pItem
, type
);
227 artwork
.insert(std::make_pair(type
, art
));
229 pItem
->AppendArt(artwork
);
232 m_videoDatabase
->Close();
237 bool CVideoThumbLoader::LoadItemLookup(CFileItem
* pItem
)
239 if (pItem
->m_bIsShareOrDrive
|| pItem
->IsParentFolder() || pItem
->GetPath() == "add")
242 if (pItem
->HasVideoInfoTag() && !pItem
->GetVideoInfoTag()->m_type
.empty() &&
243 pItem
->GetVideoInfoTag()->m_type
!= MediaTypeMovie
&&
244 pItem
->GetVideoInfoTag()->m_type
!= MediaTypeTvShow
&&
245 pItem
->GetVideoInfoTag()->m_type
!= MediaTypeEpisode
&&
246 pItem
->GetVideoInfoTag()->m_type
!= MediaTypeMusicVideo
&&
247 pItem
->GetVideoInfoTag()->m_type
!= MediaTypeVideoVersion
)
248 return false; // Nothing to do here
250 m_videoDatabase
->Open();
252 const bool isLibraryItem
= pItem
->HasVideoInfoTag() && pItem
->GetVideoInfoTag()->m_iDbId
> -1 &&
253 !pItem
->GetVideoInfoTag()->m_type
.empty();
254 const bool libraryArtFilled
=
255 pItem
->HasVideoInfoTag() && pItem
->GetProperty("libraryartfilled").asBoolean();
256 if (!isLibraryItem
|| !libraryArtFilled
)
258 std::map
<std::string
, std::string
> artwork
= pItem
->GetArt();
259 std::vector
<std::string
> artTypes
=
260 GetArtTypes(pItem
->HasVideoInfoTag() ? pItem
->GetVideoInfoTag()->m_type
: "");
261 if (find(artTypes
.begin(), artTypes
.end(), "thumb") == artTypes
.end())
262 artTypes
.emplace_back("thumb"); // always look for "thumb" art for files
263 for (std::vector
<std::string
>::const_iterator i
= artTypes
.begin(); i
!= artTypes
.end(); ++i
)
265 std::string type
= *i
;
266 if (!pItem
->HasArt(type
))
268 std::string art
= GetLocalArt(*pItem
, type
, type
== "fanart");
269 if (!art
.empty()) // cache it
271 SetCachedImage(*pItem
, type
, art
);
272 CServiceBroker::GetTextureCache()->BackgroundCacheImage(art
);
273 artwork
.insert(std::make_pair(type
, art
));
277 // If nothing was found, try embedded art
278 if (pItem
->HasVideoInfoTag() && !pItem
->GetVideoInfoTag()->m_coverArt
.empty())
280 for (auto& it
: pItem
->GetVideoInfoTag()->m_coverArt
)
282 if (it
.m_type
== type
)
284 art
= IMAGE_FILES::URLFromFile(pItem
->GetPath(), "video_" + type
);
285 artwork
.insert(std::make_pair(type
, art
));
292 pItem
->AppendArt(artwork
);
295 // We can only extract flags/thumbs for file-like items
296 if (!pItem
->m_bIsFolder
&& VIDEO::IsVideo(*pItem
))
298 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
299 if (!pItem
->HasArt("thumb"))
301 std::string thumbURL
= GetEmbeddedThumbURL(*pItem
);
302 if (CDVDFileInfo::CanExtract(*pItem
) &&
303 settings
->GetBool(CSettings::SETTING_MYVIDEOS_EXTRACTTHUMB
) &&
304 settings
->GetInt(CSettings::SETTING_VIDEOLIBRARY_ARTWORK_LEVEL
) !=
305 CSettings::VIDEOLIBRARY_ARTWORK_LEVEL_NONE
)
307 pItem
->SetArt("thumb", thumbURL
);
309 if (pItem
->HasVideoInfoTag())
311 CVideoInfoTag
* info
= pItem
->GetVideoInfoTag();
312 if (info
->m_iDbId
> 0 && !info
->m_type
.empty())
313 m_videoDatabase
->SetArtForItem(info
->m_iDbId
, info
->m_type
, "thumb", thumbURL
);
318 // flag extraction mostly for non-library items - should end up somewhere else,
319 // like a VideoInfoLoader if it existed
320 if (settings
->GetBool(CSettings::SETTING_MYVIDEOS_EXTRACTFLAGS
) &&
321 CDVDFileInfo::CanExtract(*pItem
) &&
322 (!pItem
->HasVideoInfoTag() || !pItem
->GetVideoInfoTag()->HasStreamDetails()))
324 // No tag or no details set, so extract them
325 CLog::LogF(LOGDEBUG
, "trying to extract filestream details from video file {}",
326 CURL::GetRedacted(pItem
->GetPath()));
327 if (CDVDFileInfo::GetFileStreamDetails(pItem
))
329 CVideoInfoTag
* info
= pItem
->GetVideoInfoTag();
330 m_videoDatabase
->BeginTransaction();
332 if (info
->m_iFileId
< 0)
333 m_videoDatabase
->SetStreamDetailsForFile(
334 info
->m_streamDetails
,
335 !info
->m_strFileNameAndPath
.empty() ? info
->m_strFileNameAndPath
: pItem
->GetPath());
337 m_videoDatabase
->SetStreamDetailsForFileId(info
->m_streamDetails
, info
->m_iFileId
);
339 // overwrite the runtime value if the one from streamdetails is available
340 if (info
->m_iDbId
> 0 && info
->GetStaticDuration() != info
->GetDuration())
342 info
->SetDuration(info
->GetDuration());
344 // store the updated information in the database
345 m_videoDatabase
->SetDetailsForItem(info
->m_iDbId
, info
->m_type
, *info
, pItem
->GetArt());
348 m_videoDatabase
->CommitTransaction();
352 DetectAndAddMissingItemData(*pItem
);
354 m_videoDatabase
->Close();
358 bool CVideoThumbLoader::FillLibraryArt(CFileItem
&item
)
360 CVideoInfoTag
&tag
= *item
.GetVideoInfoTag();
361 std::map
<std::string
, std::string
> artwork
;
362 // Video item can be an album - either a
363 // a) search result with full details including music library album id, or
364 // b) musicvideo album that needs matching to a music album, storing id as well as fetch art.
365 if (tag
.m_type
== MediaTypeAlbum
)
368 if (item
.HasMusicInfoTag()) // Album is a search result
369 idAlbum
= item
.GetMusicInfoTag()->GetAlbumId();
370 CMusicDatabase database
;
372 if (idAlbum
< 0 && !tag
.m_strAlbum
.empty() &&
373 item
.GetProperty("musicvideomediatype") == MediaTypeAlbum
)
375 // Musicvideo album - try to match album in music db on artist(s) and album name.
376 // Get review if available and save the matching music library album id.
377 std::string strArtist
= StringUtils::Join(
379 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator
);
380 std::string strReview
;
381 if (database
.GetMatchingMusicVideoAlbum(
382 tag
.m_strAlbum
, strArtist
, idAlbum
, strReview
))
384 item
.SetProperty("album_musicid", idAlbum
);
385 item
.SetProperty("album_description", strReview
);
388 // Get album art only (not related artist art)
389 if (database
.GetArtForItem(idAlbum
, MediaTypeAlbum
, artwork
))
390 item
.SetArt(artwork
);
393 else if (tag
.m_type
== "actor" && !tag
.m_artist
.empty() &&
394 item
.GetProperty("musicvideomediatype") == MediaTypeArtist
)
396 // Try to match artist in music db on name, get bio if available and fetch artist art
397 // Save the matching music library artist id.
398 CMusicDatabase database
;
401 int idArtist
= database
.GetArtistByName(tag
.m_artist
[0]);
404 database
.GetArtist(idArtist
, artist
);
405 tag
.m_strPlot
= artist
.strBiography
;
406 item
.SetProperty("artist_musicid", idArtist
);
408 if (database
.GetArtForItem(idArtist
, MediaTypeArtist
, artwork
))
409 item
.SetArt(artwork
);
413 if (tag
.m_iDbId
> -1 && !tag
.m_type
.empty())
415 m_videoDatabase
->Open();
417 // @todo unify asset path for other items path
418 if (VIDEO::IsVideoAssetFile(item
))
420 if (m_videoDatabase
->GetArtForAsset(
422 (item
.GetProperty("noartfallbacktoowner").asBoolean(false) ||
423 item
.GetVideoInfoTag()->GetAssetInfo().GetType() != VideoAssetType::VERSION
)
424 ? ArtFallbackOptions::NONE
425 : ArtFallbackOptions::PARENT
,
427 item
.AppendArt(artwork
);
429 else if (m_videoDatabase
->GetArtForItem(tag
.m_iDbId
, tag
.m_type
, artwork
))
431 item
.AppendArt(artwork
);
433 else if (tag
.m_type
== "actor" && !tag
.m_artist
.empty() &&
434 item
.GetProperty("musicvideomediatype") != MediaTypeArtist
)
436 // Fallback to music library for actors without art
437 //! @todo Is m_artist set other than musicvideo? Remove this fallback if not.
438 CMusicDatabase database
;
440 int idArtist
= database
.GetArtistByName(item
.GetLabel());
441 if (database
.GetArtForItem(idArtist
, MediaTypeArtist
, artwork
))
442 item
.SetArt(artwork
);
446 if (tag
.m_type
== MediaTypeEpisode
|| tag
.m_type
== MediaTypeSeason
)
448 // For episodes and seasons, we want to set fanart for that of the show
449 if (!item
.HasArt("tvshow.fanart") && tag
.m_iIdShow
>= 0)
451 const ArtMap
& artmap
= GetArtFromCache(MediaTypeTvShow
, tag
.m_iIdShow
);
454 item
.AppendArt(artmap
, MediaTypeTvShow
);
455 item
.SetArtFallback("fanart", "tvshow.fanart");
456 item
.SetArtFallback("tvshow.thumb", "tvshow.poster");
460 if (tag
.m_type
== MediaTypeEpisode
&& !item
.HasArt("season.poster") && tag
.m_iSeason
> -1)
462 const ArtMap
& artmap
= GetArtFromCache(MediaTypeSeason
, tag
.m_iIdSeason
);
464 item
.AppendArt(artmap
, MediaTypeSeason
);
467 else if (tag
.m_type
== MediaTypeMovie
&& tag
.m_set
.id
>= 0 && !item
.HasArt("set.fanart"))
469 const ArtMap
& artmap
= GetArtFromCache(MediaTypeVideoCollection
, tag
.m_set
.id
);
471 item
.AppendArt(artmap
, MediaTypeVideoCollection
);
473 m_videoDatabase
->Close();
475 item
.SetProperty("libraryartfilled", true);
476 return !item
.GetArt().empty();
479 bool CVideoThumbLoader::FillThumb(CFileItem
&item
)
481 if (item
.HasArt("thumb"))
483 std::string thumb
= GetCachedImage(item
, "thumb");
486 thumb
= GetLocalArt(item
, "thumb");
488 SetCachedImage(item
, "thumb", thumb
);
491 item
.SetArt("thumb", thumb
);
494 // If nothing was found, try embedded art
495 if (item
.HasVideoInfoTag() && !item
.GetVideoInfoTag()->m_coverArt
.empty())
497 for (auto& it
: item
.GetVideoInfoTag()->m_coverArt
)
499 if (it
.m_type
== "thumb")
501 thumb
= IMAGE_FILES::URLFromFile(item
.GetPath(), "video_" + it
.m_type
);
502 item
.SetArt(it
.m_type
, thumb
);
508 return !thumb
.empty();
511 std::string
CVideoThumbLoader::GetLocalArt(const CFileItem
&item
, const std::string
&type
, bool checkFolder
)
513 if (item
.SkipLocalArt())
516 /* Cache directory for (sub) folders with Curl("streamed") filesystems. We need to do this
517 else entering (new) directories from the app thread becomes much slower. This
518 is caused by the fact that Curl Stat/Exist() is really slow and that the
519 thumbloader thread accesses the streamed filesystem at the same time as the
520 app thread and the latter has to wait for it.
523 const auto settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
525 const bool cacheAll
=
526 settings
? settings
->GetInt(CSettings::SETTING_FILECACHE_BUFFERMODE
) == CACHE_BUFFER_MODE_ALL
529 if (item
.m_bIsFolder
&& (NETWORK::IsStreamedFilesystem(item
) || cacheAll
))
531 CFileItemList items
; // Dummy list
532 CDirectory::GetDirectory(item
.GetPath(), items
, "", DIR_FLAG_NO_FILE_DIRS
| DIR_FLAG_READ_CACHE
| DIR_FLAG_NO_FILE_INFO
);
538 art
= item
.FindLocalArt(type
+ ".jpg", checkFolder
);
540 art
= item
.FindLocalArt(type
+ ".png", checkFolder
);
542 if (art
.empty() && (type
.empty() || type
== "thumb"))
543 { // backward compatibility
544 art
= item
.FindLocalArt("", false);
545 if (art
.empty() && (checkFolder
|| (item
.m_bIsFolder
&& !item
.IsFileFolder()) || item
.IsOpticalMediaFile()))
547 art
= item
.FindLocalArt("movie.tbn", true);
548 if (art
.empty()) // try folder.jpg
549 art
= item
.FindLocalArt("folder.jpg", true);
556 std::string
CVideoThumbLoader::GetEmbeddedThumbURL(const CFileItem
&item
)
558 std::string
path(item
.GetPath());
559 if (VIDEO::IsVideoDb(item
) && item
.HasVideoInfoTag())
560 path
= item
.GetVideoInfoTag()->m_strFileNameAndPath
;
561 if (URIUtils::IsStack(path
))
562 path
= CStackDirectory::GetFirstStackedFile(path
);
564 return IMAGE_FILES::URLFromFile(path
, "video");
567 void CVideoThumbLoader::DetectAndAddMissingItemData(CFileItem
&item
)
569 // @todo remove exception for hybrid movie/folder of versions
570 if (item
.m_bIsFolder
&& !StringUtils::StartsWith(item
.GetPath(), VIDEODB_PATH_VERSION_ID_ALL
))
573 if (item
.HasVideoInfoTag())
575 CStreamDetails
& details
= item
.GetVideoInfoTag()->m_streamDetails
;
577 // add audio language properties
578 for (int i
= 1; i
<= details
.GetAudioStreamCount(); i
++)
580 std::string index
= std::to_string(i
);
581 item
.SetProperty("AudioChannels." + index
, details
.GetAudioChannels(i
));
582 item
.SetProperty("AudioCodec." + index
, details
.GetAudioCodec(i
).c_str());
583 item
.SetProperty("AudioLanguage." + index
, details
.GetAudioLanguage(i
).c_str());
586 // add subtitle language properties
587 for (int i
= 1; i
<= details
.GetSubtitleStreamCount(); i
++)
589 std::string index
= std::to_string(i
);
590 item
.SetProperty("SubtitleLanguage." + index
, details
.GetSubtitleLanguage(i
).c_str());
594 const CStereoscopicsManager
&stereoscopicsManager
= CServiceBroker::GetGUI()->GetStereoscopicsManager();
596 std::string stereoMode
;
598 // detect stereomode for videos
599 if (item
.HasVideoInfoTag())
600 stereoMode
= item
.GetVideoInfoTag()->m_streamDetails
.GetStereoMode();
602 if (stereoMode
.empty())
604 std::string path
= item
.GetPath();
605 if (VIDEO::IsVideoDb(item
) && item
.HasVideoInfoTag())
606 path
= item
.GetVideoInfoTag()->GetPath();
608 // check for custom stereomode setting in video settings
609 CVideoSettings itemVideoSettings
;
610 m_videoDatabase
->Open();
611 if (m_videoDatabase
->GetVideoSettings(item
, itemVideoSettings
) && itemVideoSettings
.m_StereoMode
!= RENDER_STEREO_MODE_OFF
)
613 stereoMode
= CStereoscopicsManager::ConvertGuiStereoModeToString(static_cast<RENDER_STEREO_MODE
>(itemVideoSettings
.m_StereoMode
));
615 m_videoDatabase
->Close();
617 // still empty, try grabbing from filename
618 //! @todo in case of too many false positives due to using the full path, extract the filename only using string utils
619 if (stereoMode
.empty())
620 stereoMode
= stereoscopicsManager
.DetectStereoModeByString(path
);
623 if (!stereoMode
.empty())
624 item
.SetProperty("stereomode", CStereoscopicsManager::NormalizeStereoMode(stereoMode
));
627 const ArtMap
& CVideoThumbLoader::GetArtFromCache(const std::string
&mediaType
, const int id
)
629 std::pair
<MediaType
, int> key
= std::make_pair(mediaType
, id
);
630 auto it
= m_artCache
.find(key
);
631 if (it
== m_artCache
.end())
634 m_videoDatabase
->GetArtForItem(id
, mediaType
, newart
);
635 it
= m_artCache
.insert(std::make_pair(key
, std::move(newart
))).first
;