Merge pull request #26166 from ksooo/improve-plugin-ctx-menus
[xbmc.git] / xbmc / utils / ArtUtils.cpp
blob6394f6c7c89f1f82bf64689cad0f5fd3c560d37c
1 /*
2 * Copyright (C) 2024 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 "ArtUtils.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "ServiceBroker.h"
14 #include "filesystem/Directory.h"
15 #include "filesystem/File.h"
16 #include "filesystem/MultiPathDirectory.h"
17 #include "filesystem/StackDirectory.h"
18 #include "music/MusicFileItemClassify.h"
19 #include "network/NetworkFileItemClassify.h"
20 #include "playlists/PlayListFileItemClassify.h"
21 #include "settings/AdvancedSettings.h"
22 #include "settings/SettingsComponent.h"
23 #include "utils/FileExtensionProvider.h"
24 #include "utils/StringUtils.h"
25 #include "utils/URIUtils.h"
26 #include "video/VideoFileItemClassify.h"
27 #include "video/VideoInfoTag.h"
29 using namespace XFILE;
31 namespace KODI::ART
34 void FillInDefaultIcon(CFileItem& item)
36 if (URIUtils::IsPVRGuideItem(item.GetPath()))
38 // epg items never have a default icon. no need to execute this expensive method.
39 // when filling epg grid window, easily tens of thousands of epg items are processed.
40 return;
43 // find the default icon for a file or folder item
44 // for files this can be the (depending on the file type)
45 // default picture for photo's
46 // default picture for songs
47 // default picture for videos
48 // default picture for shortcuts
49 // default picture for playlists
51 // for folders
52 // for .. folders the default picture for parent folder
53 // for other folders the defaultFolder.png
55 if (item.GetArt("icon").empty())
57 if (!item.m_bIsFolder)
59 /* To reduce the average runtime of this code, this list should
60 * be ordered with most frequently seen types first. Also bear
61 * in mind the complexity of the code behind the check in the
62 * case of IsWhatever() returns false.
64 if (item.IsPVRChannel())
66 if (URIUtils::IsPVRRadioChannel(item.GetPath()))
67 item.SetArt("icon", "DefaultMusicSongs.png");
68 else
69 item.SetArt("icon", "DefaultTVShows.png");
71 else if (item.IsLiveTV())
73 // Live TV Channel
74 item.SetArt("icon", "DefaultTVShows.png");
76 else if (URIUtils::IsArchive(item.GetPath()))
77 { // archive
78 item.SetArt("icon", "DefaultFile.png");
80 else if (item.IsUsablePVRRecording())
82 // PVR recording
83 item.SetArt("icon", "DefaultVideo.png");
85 else if (item.IsDeletedPVRRecording())
87 // PVR deleted recording
88 item.SetArt("icon", "DefaultVideoDeleted.png");
90 else if (item.IsPVRProvider())
92 item.SetArt("icon", "DefaultPVRProvider.png");
94 else if (PLAYLIST::IsPlayList(item) || PLAYLIST::IsSmartPlayList(item))
96 item.SetArt("icon", "DefaultPlaylist.png");
98 else if (MUSIC::IsAudio(item))
100 // audio
101 item.SetArt("icon", "DefaultAudio.png");
103 else if (VIDEO::IsVideo(item))
105 // video
106 item.SetArt("icon", "DefaultVideo.png");
108 else if (item.IsPVRTimer())
110 item.SetArt("icon", "DefaultVideo.png");
112 else if (item.IsPicture())
114 // picture
115 item.SetArt("icon", "DefaultPicture.png");
117 else if (item.IsPythonScript())
119 item.SetArt("icon", "DefaultScript.png");
121 else if (item.IsFavourite())
123 item.SetArt("icon", "DefaultFavourites.png");
125 else
127 // default icon for unknown file type
128 item.SetArt("icon", "DefaultFile.png");
131 else
133 if (PLAYLIST::IsPlayList(item) || PLAYLIST::IsSmartPlayList(item))
135 item.SetArt("icon", "DefaultPlaylist.png");
137 else if (item.IsParentFolder())
139 item.SetArt("icon", "DefaultFolderBack.png");
141 else
143 item.SetArt("icon", "DefaultFolder.png");
147 // Set the icon overlays (if applicable)
148 if (!item.HasOverlay() && !item.HasProperty("icon_never_overlay"))
150 if (URIUtils::IsInRAR(item.GetPath()))
151 item.SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR);
152 else if (URIUtils::IsInZIP(item.GetPath()))
153 item.SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP);
157 std::string GetFolderThumb(const CFileItem& item, const std::string& folderJPG /* = "folder.jpg" */)
159 std::string strFolder = item.GetPath();
161 if (item.IsStack())
163 URIUtils::GetParentPath(item.GetPath(), strFolder);
166 if (URIUtils::IsInRAR(strFolder) || URIUtils::IsInZIP(strFolder))
168 const CURL url(strFolder);
169 strFolder = URIUtils::GetDirectory(url.GetHostName());
172 if (item.IsMultiPath())
173 strFolder = CMultiPathDirectory::GetFirstPath(item.GetPath());
175 if (item.IsPlugin())
176 return "";
178 return URIUtils::AddFileToFolder(strFolder, folderJPG);
181 std::string GetLocalArt(const CFileItem& item, const std::string& artFile, bool useFolder)
183 // no retrieving of empty art files from folders
184 if (useFolder && artFile.empty())
185 return "";
187 std::string strFile = GetLocalArtBaseFilename(item, useFolder);
188 if (strFile.empty()) // empty filepath -> nothing to find
189 return "";
191 if (useFolder)
193 if (!artFile.empty())
194 return URIUtils::AddFileToFolder(strFile, artFile);
196 else
198 if (artFile.empty()) // old thumbnail matching
199 return URIUtils::ReplaceExtension(strFile, ".tbn");
200 else
201 return URIUtils::ReplaceExtension(strFile, "-" + artFile);
203 return "";
206 std::string GetLocalArtBaseFilename(const CFileItem& item, bool& useFolder)
208 std::string strFile;
209 if (item.IsStack())
211 std::string strPath;
212 URIUtils::GetParentPath(item.GetPath(), strPath);
213 strFile = URIUtils::AddFileToFolder(
214 strPath, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(item.GetPath())));
217 std::string file = strFile.empty() ? item.GetPath() : strFile;
218 if (URIUtils::IsInRAR(file) || URIUtils::IsInZIP(file))
220 std::string strPath = URIUtils::GetDirectory(file);
221 std::string strParent;
222 URIUtils::GetParentPath(strPath, strParent);
223 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(file));
226 if (item.IsMultiPath())
227 strFile = CMultiPathDirectory::GetFirstPath(item.GetPath());
229 if (item.IsOpticalMediaFile())
230 { // optical media files should be treated like folders
231 useFolder = true;
232 strFile = item.GetLocalMetadataPath();
234 else if (useFolder && !(item.m_bIsFolder && !item.IsFileFolder()))
236 file = strFile.empty() ? item.GetPath() : strFile;
237 strFile = URIUtils::GetDirectory(file);
240 if (strFile.empty())
241 strFile = item.GetDynPath();
243 return strFile;
246 std::string GetLocalFanart(const CFileItem& item)
248 if (VIDEO::IsVideoDb(item))
250 if (!item.HasVideoInfoTag())
251 return ""; // nothing can be done
252 CFileItem dbItem(item.m_bIsFolder ? item.GetVideoInfoTag()->m_strPath
253 : item.GetVideoInfoTag()->m_strFileNameAndPath,
254 item.m_bIsFolder);
255 return GetLocalFanart(dbItem);
258 std::string file2;
259 std::string file = item.GetPath();
260 if (item.IsStack())
262 std::string path;
263 URIUtils::GetParentPath(item.GetPath(), path);
264 CStackDirectory dir;
265 std::string path2;
266 path2 = dir.GetStackedTitlePath(file);
267 file = URIUtils::AddFileToFolder(path, URIUtils::GetFileName(path2));
268 CFileItem fan_item(dir.GetFirstStackedFile(item.GetPath()), false);
269 std::string TBNFile(URIUtils::ReplaceExtension(GetTBNFile(fan_item), "-fanart"));
270 file2 = URIUtils::AddFileToFolder(path, URIUtils::GetFileName(TBNFile));
273 if (URIUtils::IsInRAR(file) || URIUtils::IsInZIP(file))
275 std::string path = URIUtils::GetDirectory(file);
276 std::string parent;
277 URIUtils::GetParentPath(path, parent);
278 file = URIUtils::AddFileToFolder(parent, URIUtils::GetFileName(item.GetPath()));
281 // no local fanart available for these
282 if (NETWORK::IsInternetStream(item) || URIUtils::IsUPnP(file) || URIUtils::IsBluray(file) ||
283 item.IsLiveTV() || item.IsPlugin() || item.IsAddonsPath() || item.IsDVD() ||
284 (URIUtils::IsFTP(file) &&
285 !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs) ||
286 item.GetPath().empty())
287 return "";
289 std::string dir = URIUtils::GetDirectory(file);
291 if (dir.empty())
292 return "";
294 CFileItemList items;
295 CDirectory::GetDirectory(dir, items,
296 CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(),
297 DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
298 if (item.IsOpticalMediaFile())
299 { // grab from the optical media parent folder as well
300 CFileItemList moreItems;
301 CDirectory::GetDirectory(item.GetLocalMetadataPath(), moreItems,
302 CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(),
303 DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
304 items.Append(moreItems);
307 std::vector<std::string> fanarts = {"fanart"};
309 file = URIUtils::ReplaceExtension(file, "-fanart");
310 fanarts.insert(item.m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(file));
312 if (!file2.empty())
313 fanarts.insert(item.m_bIsFolder ? fanarts.end() : fanarts.begin(),
314 URIUtils::GetFileName(file2));
316 for (const auto& fanart : fanarts)
318 for (const auto& item : items)
320 std::string strCandidate = URIUtils::GetFileName(item->GetPath());
321 URIUtils::RemoveExtension(strCandidate);
322 std::string fanart2 = fanart;
323 URIUtils::RemoveExtension(fanart2);
324 if (StringUtils::EqualsNoCase(strCandidate, fanart2))
325 return item->GetPath();
329 return "";
332 // Gets the .tbn filename from a file or folder name.
333 // <filename>.ext -> <filename>.tbn
334 // <foldername>/ -> <foldername>.tbn
335 std::string GetTBNFile(const CFileItem& item)
337 std::string thumbFile;
338 std::string file = item.GetPath();
340 if (item.IsStack())
342 std::string path, returnPath;
343 URIUtils::GetParentPath(item.GetPath(), path);
344 CFileItem item(CStackDirectory::GetFirstStackedFile(file), false);
345 const std::string TBNFile = GetTBNFile(item);
346 returnPath = URIUtils::AddFileToFolder(path, URIUtils::GetFileName(TBNFile));
347 if (CFile::Exists(returnPath))
348 return returnPath;
350 const std::string& stackPath = CStackDirectory::GetStackedTitlePath(file);
351 file = URIUtils::AddFileToFolder(path, URIUtils::GetFileName(stackPath));
354 if (URIUtils::IsInRAR(file) || URIUtils::IsInZIP(file))
356 const std::string path = URIUtils::GetDirectory(file);
357 std::string parent;
358 URIUtils::GetParentPath(path, parent);
359 file = URIUtils::AddFileToFolder(parent, URIUtils::GetFileName(item.GetPath()));
362 CURL url(file);
363 file = url.GetFileName();
365 if (item.m_bIsFolder && !item.IsFileFolder())
366 URIUtils::RemoveSlashAtEnd(file);
368 if (!file.empty())
370 if (item.m_bIsFolder && !item.IsFileFolder())
371 thumbFile = file + ".tbn"; // folder, so just add ".tbn"
372 else
373 thumbFile = URIUtils::ReplaceExtension(file, ".tbn");
374 url.SetFileName(thumbFile);
375 thumbFile = url.Get();
377 return thumbFile;
380 } // namespace KODI::ART