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.
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
;
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.
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
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");
69 item
.SetArt("icon", "DefaultTVShows.png");
71 else if (item
.IsLiveTV())
74 item
.SetArt("icon", "DefaultTVShows.png");
76 else if (URIUtils::IsArchive(item
.GetPath()))
78 item
.SetArt("icon", "DefaultFile.png");
80 else if (item
.IsUsablePVRRecording())
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
))
101 item
.SetArt("icon", "DefaultAudio.png");
103 else if (VIDEO::IsVideo(item
))
106 item
.SetArt("icon", "DefaultVideo.png");
108 else if (item
.IsPVRTimer())
110 item
.SetArt("icon", "DefaultVideo.png");
112 else if (item
.IsPicture())
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");
127 // default icon for unknown file type
128 item
.SetArt("icon", "DefaultFile.png");
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");
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();
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());
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())
187 std::string strFile
= GetLocalArtBaseFilename(item
, useFolder
);
188 if (strFile
.empty()) // empty filepath -> nothing to find
193 if (!artFile
.empty())
194 return URIUtils::AddFileToFolder(strFile
, artFile
);
198 if (artFile
.empty()) // old thumbnail matching
199 return URIUtils::ReplaceExtension(strFile
, ".tbn");
201 return URIUtils::ReplaceExtension(strFile
, "-" + artFile
);
206 std::string
GetLocalArtBaseFilename(const CFileItem
& item
, bool& useFolder
)
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
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
);
241 strFile
= item
.GetDynPath();
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
,
255 return GetLocalFanart(dbItem
);
259 std::string file
= item
.GetPath();
263 URIUtils::GetParentPath(item
.GetPath(), path
);
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
);
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())
289 std::string dir
= URIUtils::GetDirectory(file
);
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
));
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();
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();
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
))
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
);
358 URIUtils::GetParentPath(path
, parent
);
359 file
= URIUtils::AddFileToFolder(parent
, URIUtils::GetFileName(item
.GetPath()));
363 file
= url
.GetFileName();
365 if (item
.m_bIsFolder
&& !item
.IsFileFolder())
366 URIUtils::RemoveSlashAtEnd(file
);
370 if (item
.m_bIsFolder
&& !item
.IsFileFolder())
371 thumbFile
= file
+ ".tbn"; // folder, so just add ".tbn"
373 thumbFile
= URIUtils::ReplaceExtension(file
, ".tbn");
374 url
.SetFileName(thumbFile
);
375 thumbFile
= url
.Get();
380 } // namespace KODI::ART