[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / FileItem.cpp
blob9d59e55889941c3ccf873a8e81e40aff651506a1
1 /*
2 * Copyright (C) 2005-2020 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 "FileItem.h"
11 #include "CueDocument.h"
12 #include "FileItemList.h"
13 #include "ServiceBroker.h"
14 #include "URL.h"
15 #include "Util.h"
16 #include "events/IEvent.h"
17 #include "filesystem/CurlFile.h"
18 #include "filesystem/Directory.h"
19 #include "filesystem/File.h"
20 #include "filesystem/MultiPathDirectory.h"
21 #include "filesystem/MusicDatabaseDirectory/QueryParams.h"
22 #include "filesystem/StackDirectory.h"
23 #include "filesystem/VideoDatabaseDirectory.h"
24 #include "filesystem/VideoDatabaseDirectory/QueryParams.h"
25 #include "games/GameUtils.h"
26 #include "games/tags/GameInfoTag.h"
27 #include "guilib/LocalizeStrings.h"
28 #include "media/MediaLockState.h"
29 #include "music/Album.h"
30 #include "music/Artist.h"
31 #include "music/MusicDatabase.h"
32 #include "music/MusicFileItemClassify.h"
33 #include "music/tags/MusicInfoTag.h"
34 #include "music/tags/MusicInfoTagLoaderFactory.h"
35 #include "network/NetworkFileItemClassify.h"
36 #include "pictures/PictureInfoTag.h"
37 #include "playlists/PlayList.h"
38 #include "playlists/PlayListFactory.h"
39 #include "playlists/PlayListFileItemClassify.h"
40 #include "pvr/PVRManager.h"
41 #include "pvr/channels/PVRChannel.h"
42 #include "pvr/channels/PVRChannelGroupMember.h"
43 #include "pvr/epg/EpgInfoTag.h"
44 #include "pvr/epg/EpgSearchFilter.h"
45 #include "pvr/guilib/PVRGUIActionsChannels.h"
46 #include "pvr/guilib/PVRGUIActionsEPG.h"
47 #include "pvr/guilib/PVRGUIActionsUtils.h"
48 #include "pvr/recordings/PVRRecording.h"
49 #include "pvr/timers/PVRTimerInfoTag.h"
50 #include "settings/AdvancedSettings.h"
51 #include "settings/SettingUtils.h"
52 #include "settings/Settings.h"
53 #include "settings/SettingsComponent.h"
54 #include "settings/lib/Setting.h"
55 #include "utils/Archive.h"
56 #include "utils/ArtUtils.h"
57 #include "utils/FileExtensionProvider.h"
58 #include "utils/Mime.h"
59 #include "utils/RegExp.h"
60 #include "utils/StringUtils.h"
61 #include "utils/URIUtils.h"
62 #include "utils/Variant.h"
63 #include "utils/log.h"
64 #include "video/Bookmark.h"
65 #include "video/VideoDatabase.h"
66 #include "video/VideoFileItemClassify.h"
67 #include "video/VideoInfoTag.h"
68 #include "video/VideoUtils.h"
70 #include <cstdlib>
71 #include <memory>
73 using namespace KODI;
74 using namespace XFILE;
75 using namespace PLAYLIST;
76 using namespace MUSIC_INFO;
77 using namespace PVR;
78 using namespace GAME;
80 CFileItem::CFileItem(const CSong& song)
82 Initialize();
83 SetFromSong(song);
86 CFileItem::CFileItem(const CSong& song, const CMusicInfoTag& music)
88 Initialize();
89 SetFromSong(song);
90 *GetMusicInfoTag() = music;
93 CFileItem::CFileItem(const CURL &url, const CAlbum& album)
95 Initialize();
97 m_strPath = url.Get();
98 URIUtils::AddSlashAtEnd(m_strPath);
99 SetFromAlbum(album);
102 CFileItem::CFileItem(const std::string &path, const CAlbum& album)
104 Initialize();
106 m_strPath = path;
107 URIUtils::AddSlashAtEnd(m_strPath);
108 SetFromAlbum(album);
111 CFileItem::CFileItem(const CMusicInfoTag& music)
113 Initialize();
114 SetLabel(music.GetTitle());
115 m_strPath = music.GetURL();
116 m_bIsFolder = URIUtils::HasSlashAtEnd(m_strPath);
117 *GetMusicInfoTag() = music;
118 FillInDefaultIcon();
119 FillInMimeType(false);
122 CFileItem::CFileItem(const CVideoInfoTag& movie)
124 Initialize();
125 SetFromVideoInfoTag(movie);
128 void CFileItem::FillMusicInfoTag(const std::shared_ptr<const CPVREpgInfoTag>& tag)
130 CMusicInfoTag* musictag = GetMusicInfoTag(); // create (!) the music tag.
132 musictag->SetTitle(CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().GetTitleForEpgTag(tag));
134 if (tag)
136 musictag->SetGenre(tag->Genre());
137 musictag->SetDuration(tag->GetDuration());
138 musictag->SetURL(tag->Path());
141 musictag->SetLoaded(true);
144 CFileItem::CFileItem(const std::shared_ptr<CPVREpgInfoTag>& tag)
146 Initialize();
148 m_bIsFolder = false;
149 m_epgInfoTag = tag;
150 m_strPath = tag->Path();
151 m_bCanQueue = false;
152 SetLabel(CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().GetTitleForEpgTag(tag));
153 m_dateTime = tag->StartAsLocalTime();
155 if (!tag->IconPath().empty())
157 SetArt("icon", tag->IconPath());
159 else
161 const std::string iconPath = tag->ChannelIconPath();
162 if (!iconPath.empty())
163 SetArt("icon", iconPath);
164 else if (tag->IsRadio())
165 SetArt("icon", "DefaultMusicSongs.png");
166 else
167 SetArt("icon", "DefaultTVShows.png");
170 // Speedup FillInDefaultIcon()
171 SetProperty("icon_never_overlay", true);
173 if (tag->IsRadio() && !HasMusicInfoTag())
174 FillMusicInfoTag(tag);
176 FillInMimeType(false);
179 CFileItem::CFileItem(const std::shared_ptr<PVR::CPVREpgSearchFilter>& filter)
181 Initialize();
183 m_bIsFolder = true;
184 m_epgSearchFilter = filter;
185 m_strPath = filter->GetPath();
186 m_bCanQueue = false;
187 SetLabel(filter->GetTitle());
189 const CDateTime lastExec = filter->GetLastExecutedDateTime();
190 if (lastExec.IsValid())
191 m_dateTime.SetFromUTCDateTime(lastExec);
193 SetArt("icon", "DefaultPVRSearch.png");
195 // Speedup FillInDefaultIcon()
196 SetProperty("icon_never_overlay", true);
198 FillInMimeType(false);
201 CFileItem::CFileItem(const std::shared_ptr<CPVRChannelGroupMember>& channelGroupMember)
203 Initialize();
205 const std::shared_ptr<const CPVRChannel> channel = channelGroupMember->Channel();
207 m_pvrChannelGroupMemberInfoTag = channelGroupMember;
209 m_strPath = channelGroupMember->Path();
210 m_bIsFolder = false;
211 m_bCanQueue = false;
212 SetLabel(channel->ChannelName());
214 if (!channel->IconPath().empty())
215 SetArt("icon", channel->IconPath());
216 else if (channel->IsRadio())
217 SetArt("icon", "DefaultMusicSongs.png");
218 else
219 SetArt("icon", "DefaultTVShows.png");
221 SetProperty("channelid", channel->ChannelID());
222 SetProperty("path", channelGroupMember->Path());
223 SetArt("thumb", channel->IconPath());
225 // Speedup FillInDefaultIcon()
226 SetProperty("icon_never_overlay", true);
228 if (channel->IsRadio() && !HasMusicInfoTag())
230 const std::shared_ptr<const CPVREpgInfoTag> epgNow = channel->GetEPGNow();
231 FillMusicInfoTag(epgNow);
233 FillInMimeType(false);
236 CFileItem::CFileItem(const std::shared_ptr<CPVRRecording>& record)
238 Initialize();
240 m_bIsFolder = false;
241 m_pvrRecordingInfoTag = record;
242 m_strPath = record->m_strFileNameAndPath;
243 SetLabel(record->m_strTitle);
244 m_dateTime = record->RecordingTimeAsLocalTime();
245 m_dwSize = record->GetSizeInBytes();
246 m_bCanQueue = true;
248 // Set art
249 if (!record->IconPath().empty())
250 SetArt("icon", record->IconPath());
251 else
253 const std::shared_ptr<const CPVRChannel> channel = record->Channel();
254 if (channel && !channel->IconPath().empty())
255 SetArt("icon", channel->IconPath());
256 else if (record->IsRadio())
257 SetArt("icon", "DefaultMusicSongs.png");
258 else
259 SetArt("icon", "DefaultTVShows.png");
262 if (!record->ThumbnailPath().empty())
263 SetArt("thumb", record->ThumbnailPath());
265 if (!record->FanartPath().empty())
266 SetArt("fanart", record->FanartPath());
268 // Speedup FillInDefaultIcon()
269 SetProperty("icon_never_overlay", true);
271 FillInMimeType(false);
274 CFileItem::CFileItem(const std::shared_ptr<CPVRTimerInfoTag>& timer)
276 Initialize();
278 m_bIsFolder = timer->IsTimerRule();
279 m_pvrTimerInfoTag = timer;
280 m_strPath = timer->Path();
281 SetLabel(timer->Title());
282 m_dateTime = timer->StartAsLocalTime();
283 m_bCanQueue = false;
285 if (!timer->ChannelIcon().empty())
286 SetArt("icon", timer->ChannelIcon());
287 else if (timer->IsRadio())
288 SetArt("icon", "DefaultMusicSongs.png");
289 else
290 SetArt("icon", "DefaultTVShows.png");
292 // Speedup FillInDefaultIcon()
293 SetProperty("icon_never_overlay", true);
295 FillInMimeType(false);
298 CFileItem::CFileItem(const CArtist& artist)
300 Initialize();
301 SetLabel(artist.strArtist);
302 m_strPath = artist.strArtist;
303 m_bIsFolder = true;
304 URIUtils::AddSlashAtEnd(m_strPath);
305 GetMusicInfoTag()->SetArtist(artist);
306 FillInMimeType(false);
309 CFileItem::CFileItem(const CGenre& genre)
311 Initialize();
312 SetLabel(genre.strGenre);
313 m_strPath = genre.strGenre;
314 m_bIsFolder = true;
315 URIUtils::AddSlashAtEnd(m_strPath);
316 GetMusicInfoTag()->SetGenre(genre.strGenre);
317 FillInMimeType(false);
320 CFileItem::CFileItem(const CFileItem& item)
321 : CGUIListItem(item),
322 m_musicInfoTag(NULL),
323 m_videoInfoTag(NULL),
324 m_pictureInfoTag(NULL),
325 m_gameInfoTag(NULL)
327 *this = item;
330 CFileItem::CFileItem(const CGUIListItem& item)
332 Initialize();
333 // not particularly pretty, but it gets around the issue of Initialize() defaulting
334 // parameters in the CGUIListItem base class.
335 *static_cast<CGUIListItem*>(this) = item;
337 FillInMimeType(false);
340 CFileItem::CFileItem(void)
342 Initialize();
345 CFileItem::CFileItem(const std::string& strLabel)
347 Initialize();
348 SetLabel(strLabel);
351 CFileItem::CFileItem(const char* strLabel)
353 Initialize();
354 SetLabel(std::string(strLabel));
357 CFileItem::CFileItem(const CURL& path, bool bIsFolder)
359 Initialize();
360 m_strPath = path.Get();
361 m_bIsFolder = bIsFolder;
362 if (m_bIsFolder && !m_strPath.empty() && !IsFileFolder())
363 URIUtils::AddSlashAtEnd(m_strPath);
364 FillInMimeType(false);
367 CFileItem::CFileItem(const std::string& strPath, bool bIsFolder)
369 Initialize();
370 m_strPath = strPath;
371 m_bIsFolder = bIsFolder;
372 if (m_bIsFolder && !m_strPath.empty() && !IsFileFolder())
373 URIUtils::AddSlashAtEnd(m_strPath);
374 FillInMimeType(false);
377 CFileItem::CFileItem(const CMediaSource& share)
379 Initialize();
380 m_bIsFolder = true;
381 m_bIsShareOrDrive = true;
382 m_strPath = share.strPath;
383 if (!IsRSS()) // no slash at end for rss feeds
384 URIUtils::AddSlashAtEnd(m_strPath);
385 std::string label = share.strName;
386 if (!share.strStatus.empty())
387 label = StringUtils::Format("{} ({})", share.strName, share.strStatus);
388 SetLabel(label);
389 m_iLockMode = share.m_iLockMode;
390 m_strLockCode = share.m_strLockCode;
391 m_iHasLock = share.m_iHasLock;
392 m_iBadPwdCount = share.m_iBadPwdCount;
393 m_iDriveType = share.m_iDriveType;
394 SetArt("thumb", share.m_strThumbnailImage);
395 SetLabelPreformatted(true);
396 if (IsDVD())
397 GetVideoInfoTag()->m_strFileNameAndPath = share.strDiskUniqueId; // share.strDiskUniqueId contains disc unique id
398 FillInMimeType(false);
401 CFileItem::CFileItem(std::shared_ptr<const ADDON::IAddon> addonInfo) : m_addonInfo(std::move(addonInfo))
403 Initialize();
406 CFileItem::CFileItem(const EventPtr& eventLogEntry)
408 Initialize();
410 m_eventLogEntry = eventLogEntry;
411 SetLabel(eventLogEntry->GetLabel());
412 m_dateTime = eventLogEntry->GetDateTime();
413 if (!eventLogEntry->GetIcon().empty())
414 SetArt("icon", eventLogEntry->GetIcon());
417 CFileItem::~CFileItem(void)
419 delete m_musicInfoTag;
420 delete m_videoInfoTag;
421 delete m_pictureInfoTag;
422 delete m_gameInfoTag;
424 m_musicInfoTag = NULL;
425 m_videoInfoTag = NULL;
426 m_pictureInfoTag = NULL;
427 m_gameInfoTag = NULL;
430 CFileItem& CFileItem::operator=(const CFileItem& item)
432 if (this == &item)
433 return *this;
435 CGUIListItem::operator=(item);
436 m_bLabelPreformatted=item.m_bLabelPreformatted;
437 FreeMemory();
438 m_strPath = item.m_strPath;
439 m_strDynPath = item.m_strDynPath;
440 m_bIsParentFolder = item.m_bIsParentFolder;
441 m_iDriveType = item.m_iDriveType;
442 m_bIsShareOrDrive = item.m_bIsShareOrDrive;
443 m_dateTime = item.m_dateTime;
444 m_dwSize = item.m_dwSize;
446 if (item.m_musicInfoTag)
448 if (m_musicInfoTag)
449 *m_musicInfoTag = *item.m_musicInfoTag;
450 else
451 m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag(*item.m_musicInfoTag);
453 else
455 delete m_musicInfoTag;
456 m_musicInfoTag = NULL;
459 if (item.m_videoInfoTag)
461 if (m_videoInfoTag)
462 *m_videoInfoTag = *item.m_videoInfoTag;
463 else
464 m_videoInfoTag = new CVideoInfoTag(*item.m_videoInfoTag);
466 else
468 delete m_videoInfoTag;
469 m_videoInfoTag = NULL;
472 if (item.m_pictureInfoTag)
474 if (m_pictureInfoTag)
475 *m_pictureInfoTag = *item.m_pictureInfoTag;
476 else
477 m_pictureInfoTag = new CPictureInfoTag(*item.m_pictureInfoTag);
479 else
481 delete m_pictureInfoTag;
482 m_pictureInfoTag = NULL;
485 if (item.m_gameInfoTag)
487 if (m_gameInfoTag)
488 *m_gameInfoTag = *item.m_gameInfoTag;
489 else
490 m_gameInfoTag = new CGameInfoTag(*item.m_gameInfoTag);
492 else
494 delete m_gameInfoTag;
495 m_gameInfoTag = NULL;
498 m_epgInfoTag = item.m_epgInfoTag;
499 m_epgSearchFilter = item.m_epgSearchFilter;
500 m_pvrChannelGroupMemberInfoTag = item.m_pvrChannelGroupMemberInfoTag;
501 m_pvrRecordingInfoTag = item.m_pvrRecordingInfoTag;
502 m_pvrTimerInfoTag = item.m_pvrTimerInfoTag;
503 m_addonInfo = item.m_addonInfo;
504 m_eventLogEntry = item.m_eventLogEntry;
506 m_lStartOffset = item.m_lStartOffset;
507 m_lStartPartNumber = item.m_lStartPartNumber;
508 m_lEndOffset = item.m_lEndOffset;
509 m_strDVDLabel = item.m_strDVDLabel;
510 m_strTitle = item.m_strTitle;
511 m_iprogramCount = item.m_iprogramCount;
512 m_idepth = item.m_idepth;
513 m_iLockMode = item.m_iLockMode;
514 m_strLockCode = item.m_strLockCode;
515 m_iHasLock = item.m_iHasLock;
516 m_iBadPwdCount = item.m_iBadPwdCount;
517 m_bCanQueue=item.m_bCanQueue;
518 m_mimetype = item.m_mimetype;
519 m_extrainfo = item.m_extrainfo;
520 m_specialSort = item.m_specialSort;
521 m_bIsAlbum = item.m_bIsAlbum;
522 m_doContentLookup = item.m_doContentLookup;
523 return *this;
526 void CFileItem::Initialize()
528 m_musicInfoTag = NULL;
529 m_videoInfoTag = NULL;
530 m_pictureInfoTag = NULL;
531 m_gameInfoTag = NULL;
532 m_bLabelPreformatted = false;
533 m_bIsAlbum = false;
534 m_dwSize = 0;
535 m_bIsParentFolder = false;
536 m_bIsShareOrDrive = false;
537 m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
538 m_lStartOffset = 0;
539 m_lStartPartNumber = 1;
540 m_lEndOffset = 0;
541 m_iprogramCount = 0;
542 m_idepth = 1;
543 m_iLockMode = LOCK_MODE_EVERYONE;
544 m_iBadPwdCount = 0;
545 m_iHasLock = LOCK_STATE_NO_LOCK;
546 m_bCanQueue = true;
547 m_specialSort = SortSpecialNone;
548 m_doContentLookup = true;
551 void CFileItem::Reset()
553 // CGUIListItem members...
554 m_strLabel2.clear();
555 SetLabel("");
556 FreeIcons();
557 m_overlayIcon = ICON_OVERLAY_NONE;
558 m_bSelected = false;
559 m_bIsFolder = false;
561 m_strDVDLabel.clear();
562 m_strTitle.clear();
563 m_strPath.clear();
564 m_strDynPath.clear();
565 m_dateTime.Reset();
566 m_strLockCode.clear();
567 m_mimetype.clear();
568 delete m_musicInfoTag;
569 m_musicInfoTag=NULL;
570 delete m_videoInfoTag;
571 m_videoInfoTag=NULL;
572 m_epgInfoTag.reset();
573 m_epgSearchFilter.reset();
574 m_pvrChannelGroupMemberInfoTag.reset();
575 m_pvrRecordingInfoTag.reset();
576 m_pvrTimerInfoTag.reset();
577 delete m_pictureInfoTag;
578 m_pictureInfoTag=NULL;
579 delete m_gameInfoTag;
580 m_gameInfoTag = NULL;
581 m_extrainfo.clear();
582 ClearProperties();
583 m_eventLogEntry.reset();
585 Initialize();
586 SetInvalid();
589 // do not archive dynamic path
590 void CFileItem::Archive(CArchive& ar)
592 CGUIListItem::Archive(ar);
594 if (ar.IsStoring())
596 ar << m_bIsParentFolder;
597 ar << m_bLabelPreformatted;
598 ar << m_strPath;
599 ar << m_bIsShareOrDrive;
600 ar << m_iDriveType;
601 ar << m_dateTime;
602 ar << m_dwSize;
603 ar << m_strDVDLabel;
604 ar << m_strTitle;
605 ar << m_iprogramCount;
606 ar << m_idepth;
607 ar << m_lStartOffset;
608 ar << m_lStartPartNumber;
609 ar << m_lEndOffset;
610 ar << m_iLockMode;
611 ar << m_strLockCode;
612 ar << m_iBadPwdCount;
614 ar << m_bCanQueue;
615 ar << m_mimetype;
616 ar << m_extrainfo;
617 ar << m_specialSort;
618 ar << m_doContentLookup;
620 if (m_musicInfoTag)
622 ar << 1;
623 ar << *m_musicInfoTag;
625 else
626 ar << 0;
627 if (m_videoInfoTag)
629 ar << 1;
630 ar << *m_videoInfoTag;
632 else
633 ar << 0;
634 if (m_pictureInfoTag)
636 ar << 1;
637 ar << *m_pictureInfoTag;
639 else
640 ar << 0;
641 if (m_gameInfoTag)
643 ar << 1;
644 ar << *m_gameInfoTag;
646 else
647 ar << 0;
649 else
651 ar >> m_bIsParentFolder;
652 ar >> m_bLabelPreformatted;
653 ar >> m_strPath;
654 ar >> m_bIsShareOrDrive;
655 ar >> m_iDriveType;
656 ar >> m_dateTime;
657 ar >> m_dwSize;
658 ar >> m_strDVDLabel;
659 ar >> m_strTitle;
660 ar >> m_iprogramCount;
661 ar >> m_idepth;
662 ar >> m_lStartOffset;
663 ar >> m_lStartPartNumber;
664 ar >> m_lEndOffset;
665 int temp;
666 ar >> temp;
667 m_iLockMode = (LockType)temp;
668 ar >> m_strLockCode;
669 ar >> m_iBadPwdCount;
671 ar >> m_bCanQueue;
672 ar >> m_mimetype;
673 ar >> m_extrainfo;
674 ar >> temp;
675 m_specialSort = (SortSpecial)temp;
676 ar >> m_doContentLookup;
678 int iType;
679 ar >> iType;
680 if (iType == 1)
681 ar >> *GetMusicInfoTag();
682 ar >> iType;
683 if (iType == 1)
684 ar >> *GetVideoInfoTag();
685 ar >> iType;
686 if (iType == 1)
687 ar >> *GetPictureInfoTag();
688 ar >> iType;
689 if (iType == 1)
690 ar >> *GetGameInfoTag();
692 SetInvalid();
696 void CFileItem::Serialize(CVariant& value) const
698 //CGUIListItem::Serialize(value["CGUIListItem"]);
700 value["strPath"] = m_strPath;
701 value["dateTime"] = (m_dateTime.IsValid()) ? m_dateTime.GetAsRFC1123DateTime() : "";
702 value["lastmodified"] = m_dateTime.IsValid() ? m_dateTime.GetAsDBDateTime() : "";
703 value["size"] = m_dwSize;
704 value["DVDLabel"] = m_strDVDLabel;
705 value["title"] = m_strTitle;
706 value["mimetype"] = m_mimetype;
707 value["extrainfo"] = m_extrainfo;
709 if (m_musicInfoTag)
710 (*m_musicInfoTag).Serialize(value["musicInfoTag"]);
712 if (m_videoInfoTag)
713 (*m_videoInfoTag).Serialize(value["videoInfoTag"]);
715 if (m_pictureInfoTag)
716 (*m_pictureInfoTag).Serialize(value["pictureInfoTag"]);
718 if (m_gameInfoTag)
719 (*m_gameInfoTag).Serialize(value["gameInfoTag"]);
721 if (!m_mapProperties.empty())
723 auto& customProperties = value["customproperties"];
724 for (const auto& prop : m_mapProperties)
725 customProperties[prop.first] = prop.second;
729 void CFileItem::ToSortable(SortItem &sortable, Field field) const
731 switch (field)
733 case FieldPath:
734 sortable[FieldPath] = m_strPath;
735 break;
736 case FieldDate:
737 sortable[FieldDate] = (m_dateTime.IsValid()) ? m_dateTime.GetAsDBDateTime() : "";
738 break;
739 case FieldSize:
740 sortable[FieldSize] = m_dwSize;
741 break;
742 case FieldDriveType:
743 sortable[FieldDriveType] = m_iDriveType;
744 break;
745 case FieldStartOffset:
746 sortable[FieldStartOffset] = m_lStartOffset;
747 break;
748 case FieldEndOffset:
749 sortable[FieldEndOffset] = m_lEndOffset;
750 break;
751 case FieldProgramCount:
752 sortable[FieldProgramCount] = m_iprogramCount;
753 break;
754 case FieldBitrate:
755 sortable[FieldBitrate] = m_dwSize;
756 break;
757 case FieldTitle:
758 sortable[FieldTitle] = m_strTitle;
759 break;
761 // If there's ever a need to convert more properties from CGUIListItem it might be
762 // worth to make CGUIListItem implement ISortable as well and call it from here
764 default:
765 break;
768 if (HasMusicInfoTag())
769 GetMusicInfoTag()->ToSortable(sortable, field);
771 if (HasVideoInfoTag())
772 GetVideoInfoTag()->ToSortable(sortable, field);
774 if (HasPictureInfoTag())
775 GetPictureInfoTag()->ToSortable(sortable, field);
777 if (HasPVRChannelInfoTag())
778 GetPVRChannelInfoTag()->ToSortable(sortable, field);
780 if (HasPVRChannelGroupMemberInfoTag())
781 GetPVRChannelGroupMemberInfoTag()->ToSortable(sortable, field);
783 if (HasAddonInfo())
785 switch (field)
787 case FieldInstallDate:
788 sortable[FieldInstallDate] = GetAddonInfo()->InstallDate().GetAsDBDateTime();
789 break;
790 case FieldLastUpdated:
791 sortable[FieldLastUpdated] = GetAddonInfo()->LastUpdated().GetAsDBDateTime();
792 break;
793 case FieldLastUsed:
794 sortable[FieldLastUsed] = GetAddonInfo()->LastUsed().GetAsDBDateTime();
795 break;
796 default:
797 break;
801 if (HasGameInfoTag())
802 GetGameInfoTag()->ToSortable(sortable, field);
804 if (m_eventLogEntry)
805 m_eventLogEntry->ToSortable(sortable, field);
807 if (IsFavourite())
809 if (field == FieldUserPreference)
810 sortable[FieldUserPreference] = GetProperty("favourite.index").asString();
814 void CFileItem::ToSortable(SortItem &sortable, const Fields &fields) const
816 Fields::const_iterator it;
817 for (it = fields.begin(); it != fields.end(); ++it)
818 ToSortable(sortable, *it);
820 /* FieldLabel is used as a fallback by all sorters and therefore has to be present as well */
821 sortable[FieldLabel] = GetLabel();
822 /* FieldSortSpecial and FieldFolder are required in conjunction with all other sorters as well */
823 sortable[FieldSortSpecial] = m_specialSort;
824 sortable[FieldFolder] = m_bIsFolder;
827 bool CFileItem::Exists(bool bUseCache /* = true */) const
829 if (m_strPath.empty() || IsPath("add") || NETWORK::IsInternetStream(*this) || IsParentFolder() ||
830 IsVirtualDirectoryRoot() || IsPlugin() || IsPVR())
831 return true;
833 if (VIDEO::IsVideoDb(*this) && HasVideoInfoTag())
835 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
836 return dbItem.Exists();
839 std::string strPath = m_strPath;
841 if (URIUtils::IsMultiPath(strPath))
842 strPath = CMultiPathDirectory::GetFirstPath(strPath);
844 if (URIUtils::IsStack(strPath))
845 strPath = CStackDirectory::GetFirstStackedFile(strPath);
847 if (m_bIsFolder)
848 return CDirectory::Exists(strPath, bUseCache);
849 else
850 return CFile::Exists(strPath, bUseCache);
852 return false;
855 bool CFileItem::IsEPG() const
857 return HasEPGInfoTag();
860 bool CFileItem::IsPVRChannel() const
862 return HasPVRChannelInfoTag();
865 bool CFileItem::IsPVRChannelGroup() const
867 return URIUtils::IsPVRChannelGroup(m_strPath);
870 bool CFileItem::IsPVRRecording() const
872 return HasPVRRecordingInfoTag();
875 bool CFileItem::IsUsablePVRRecording() const
877 return (m_pvrRecordingInfoTag && !m_pvrRecordingInfoTag->IsDeleted());
880 bool CFileItem::IsDeletedPVRRecording() const
882 return (m_pvrRecordingInfoTag && m_pvrRecordingInfoTag->IsDeleted());
885 bool CFileItem::IsInProgressPVRRecording() const
887 return (m_pvrRecordingInfoTag && m_pvrRecordingInfoTag->IsInProgress());
890 bool CFileItem::IsPVRTimer() const
892 return HasPVRTimerInfoTag();
895 bool CFileItem::IsDeleted() const
897 if (HasPVRRecordingInfoTag())
898 return GetPVRRecordingInfoTag()->IsDeleted();
900 return false;
903 bool CFileItem::IsGame() const
905 if (HasGameInfoTag())
906 return true;
908 if (HasVideoInfoTag())
909 return false;
911 if (HasMusicInfoTag())
912 return false;
914 if (HasPictureInfoTag())
915 return false;
917 if (IsPVR())
918 return false;
920 if (HasAddonInfo())
921 return CGameUtils::IsStandaloneGame(std::const_pointer_cast<ADDON::IAddon>(GetAddonInfo()));
923 return CGameUtils::HasGameExtension(m_strPath);
926 bool CFileItem::IsPicture() const
928 if (StringUtils::StartsWithNoCase(m_mimetype, "image/"))
929 return true;
931 if (HasPictureInfoTag())
932 return true;
934 if (HasGameInfoTag())
935 return false;
937 if (HasMusicInfoTag())
938 return false;
940 if (HasVideoInfoTag())
941 return false;
943 if (HasPVRTimerInfoTag() || HasPVRChannelInfoTag() || HasPVRChannelGroupMemberInfoTag() ||
944 HasPVRRecordingInfoTag() || HasEPGInfoTag() || HasEPGSearchFilter())
945 return false;
947 if (!m_strPath.empty())
948 return CUtil::IsPicture(m_strPath);
950 return false;
953 bool CFileItem::IsFileFolder(EFileFolderType types) const
955 EFileFolderType always_type = EFILEFOLDER_TYPE_ALWAYS;
957 /* internet streams are not directly expanded */
958 if (NETWORK::IsInternetStream(*this))
959 always_type = EFILEFOLDER_TYPE_ONCLICK;
961 // strm files are not browsable
962 if (IsType(".strm") && (types & EFILEFOLDER_TYPE_ONBROWSE))
963 return false;
965 if (types & always_type)
967 if (PLAYLIST::IsSmartPlayList(*this) ||
968 (PLAYLIST::IsPlayList(*this) &&
969 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_playlistAsFolders) ||
970 IsAPK() || IsZIP() || IsRAR() || IsRSS() || MUSIC::IsAudioBook(*this) ||
971 IsType(".ogg|.oga|.xbt")
972 #if defined(TARGET_ANDROID)
973 || IsType(".apk")
974 #endif
976 return true;
979 if (CServiceBroker::IsAddonInterfaceUp() &&
980 IsType(CServiceBroker::GetFileExtensionProvider().GetFileFolderExtensions().c_str()) &&
981 CServiceBroker::GetFileExtensionProvider().CanOperateExtension(m_strPath))
982 return true;
984 if(types & EFILEFOLDER_TYPE_ONBROWSE)
986 if ((PLAYLIST::IsPlayList(*this) &&
987 !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_playlistAsFolders) ||
988 IsDiscImage())
989 return true;
992 return false;
995 bool CFileItem::IsLibraryFolder() const
997 if (HasProperty("library.filter") && GetProperty("library.filter").asBoolean())
998 return true;
1000 return URIUtils::IsLibraryFolder(m_strPath);
1003 bool CFileItem::IsPythonScript() const
1005 return URIUtils::HasExtension(m_strPath, ".py");
1008 bool CFileItem::IsType(const char *ext) const
1010 if (!m_strDynPath.empty())
1011 return URIUtils::HasExtension(m_strDynPath, ext);
1013 return URIUtils::HasExtension(m_strPath, ext);
1016 bool CFileItem::IsNFO() const
1018 return URIUtils::HasExtension(m_strPath, ".nfo");
1021 bool CFileItem::IsDiscImage() const
1023 return URIUtils::IsDiscImage(GetDynPath());
1026 bool CFileItem::IsOpticalMediaFile() const
1028 if (VIDEO::IsDVDFile(*this, false, true))
1029 return true;
1031 return VIDEO::IsBDFile(*this);
1034 bool CFileItem::IsRAR() const
1036 return URIUtils::IsRAR(m_strPath);
1039 bool CFileItem::IsAPK() const
1041 return URIUtils::IsAPK(m_strPath);
1044 bool CFileItem::IsZIP() const
1046 return URIUtils::IsZIP(m_strPath);
1049 bool CFileItem::IsCBZ() const
1051 return URIUtils::HasExtension(m_strPath, ".cbz");
1054 bool CFileItem::IsCBR() const
1056 return URIUtils::HasExtension(m_strPath, ".cbr");
1059 bool CFileItem::IsRSS() const
1061 return StringUtils::StartsWithNoCase(m_strPath, "rss://") || URIUtils::HasExtension(m_strPath, ".rss")
1062 || StringUtils::StartsWithNoCase(m_strPath, "rsss://")
1063 || m_mimetype == "application/rss+xml";
1066 bool CFileItem::IsAndroidApp() const
1068 return URIUtils::IsAndroidApp(m_strPath);
1071 bool CFileItem::IsStack() const
1073 return URIUtils::IsStack(GetDynPath());
1076 bool CFileItem::IsFavourite() const
1078 return URIUtils::IsFavourite(m_strPath);
1081 bool CFileItem::IsPlugin() const
1083 return URIUtils::IsPlugin(m_strPath);
1086 bool CFileItem::IsScript() const
1088 return URIUtils::IsScript(m_strPath);
1091 bool CFileItem::IsAddonsPath() const
1093 return URIUtils::IsAddonsPath(m_strPath);
1096 bool CFileItem::IsSourcesPath() const
1098 return URIUtils::IsSourcesPath(m_strPath);
1101 bool CFileItem::IsMultiPath() const
1103 return URIUtils::IsMultiPath(m_strPath);
1106 bool CFileItem::IsBluray() const
1108 if (URIUtils::IsBluray(m_strPath))
1109 return true;
1111 CFileItem item = CFileItem(VIDEO::UTILS::GetOpticalMediaPath(*this), false);
1113 return VIDEO::IsBDFile(item);
1116 bool CFileItem::IsDVD() const
1118 return URIUtils::IsDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1121 bool CFileItem::IsOnDVD() const
1123 return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1126 bool CFileItem::IsNfs() const
1128 return URIUtils::IsNfs(m_strPath);
1131 bool CFileItem::IsISO9660() const
1133 return URIUtils::IsISO9660(m_strPath);
1136 bool CFileItem::IsSmb() const
1138 return URIUtils::IsSmb(m_strPath);
1141 bool CFileItem::IsURL() const
1143 return URIUtils::IsURL(m_strPath);
1146 bool CFileItem::IsPVR() const
1148 return URIUtils::IsPVR(m_strPath);
1151 bool CFileItem::IsLiveTV() const
1153 return URIUtils::IsLiveTV(m_strPath);
1156 bool CFileItem::IsHD() const
1158 return URIUtils::IsHD(m_strPath);
1161 bool CFileItem::IsVirtualDirectoryRoot() const
1163 return (m_bIsFolder && m_strPath.empty());
1166 bool CFileItem::IsRemovable() const
1168 return IsOnDVD() || MUSIC::IsCDDA(*this) || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE;
1171 bool CFileItem::IsReadOnly() const
1173 if (IsParentFolder())
1174 return true;
1176 if (m_bIsShareOrDrive)
1177 return true;
1179 return !CUtil::SupportsWriteFileOperations(m_strPath);
1182 void CFileItem::FillInDefaultIcon()
1184 if (URIUtils::IsPVRGuideItem(m_strPath))
1186 // epg items never have a default icon. no need to execute this expensive method.
1187 // when filling epg grid window, easily tens of thousands of epg items are processed.
1188 return;
1191 //CLog::Log(LOGINFO, "FillInDefaultIcon({})", pItem->GetLabel());
1192 // find the default icon for a file or folder item
1193 // for files this can be the (depending on the file type)
1194 // default picture for photo's
1195 // default picture for songs
1196 // default picture for videos
1197 // default picture for shortcuts
1198 // default picture for playlists
1200 // for folders
1201 // for .. folders the default picture for parent folder
1202 // for other folders the defaultFolder.png
1204 if (GetArt("icon").empty())
1206 if (!m_bIsFolder)
1208 /* To reduce the average runtime of this code, this list should
1209 * be ordered with most frequently seen types first. Also bear
1210 * in mind the complexity of the code behind the check in the
1211 * case of IsWhatever() returns false.
1213 if (IsPVRChannel())
1215 if (GetPVRChannelInfoTag()->IsRadio())
1216 SetArt("icon", "DefaultMusicSongs.png");
1217 else
1218 SetArt("icon", "DefaultTVShows.png");
1220 else if ( IsLiveTV() )
1222 // Live TV Channel
1223 SetArt("icon", "DefaultTVShows.png");
1225 else if ( URIUtils::IsArchive(m_strPath) )
1226 { // archive
1227 SetArt("icon", "DefaultFile.png");
1229 else if ( IsUsablePVRRecording() )
1231 // PVR recording
1232 SetArt("icon", "DefaultVideo.png");
1234 else if ( IsDeletedPVRRecording() )
1236 // PVR deleted recording
1237 SetArt("icon", "DefaultVideoDeleted.png");
1239 else if (PLAYLIST::IsPlayList(*this) || PLAYLIST::IsSmartPlayList(*this))
1241 SetArt("icon", "DefaultPlaylist.png");
1243 else if (MUSIC::IsAudio(*this))
1245 // audio
1246 SetArt("icon", "DefaultAudio.png");
1248 else if (VIDEO::IsVideo(*this))
1250 // video
1251 SetArt("icon", "DefaultVideo.png");
1253 else if (IsPVRTimer())
1255 SetArt("icon", "DefaultVideo.png");
1257 else if ( IsPicture() )
1259 // picture
1260 SetArt("icon", "DefaultPicture.png");
1262 else if ( IsPythonScript() )
1264 SetArt("icon", "DefaultScript.png");
1266 else if (IsFavourite())
1268 SetArt("icon", "DefaultFavourites.png");
1270 else
1272 // default icon for unknown file type
1273 SetArt("icon", "DefaultFile.png");
1276 else
1278 if (PLAYLIST::IsPlayList(*this) || PLAYLIST::IsSmartPlayList(*this))
1280 SetArt("icon", "DefaultPlaylist.png");
1282 else if (IsParentFolder())
1284 SetArt("icon", "DefaultFolderBack.png");
1286 else
1288 SetArt("icon", "DefaultFolder.png");
1292 // Set the icon overlays (if applicable)
1293 if (!HasOverlay() && !HasProperty("icon_never_overlay"))
1295 if (URIUtils::IsInRAR(m_strPath))
1296 SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR);
1297 else if (URIUtils::IsInZIP(m_strPath))
1298 SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP);
1302 void CFileItem::RemoveExtension()
1304 if (m_bIsFolder)
1305 return;
1307 std::string strLabel = GetLabel();
1308 URIUtils::RemoveExtension(strLabel);
1309 SetLabel(strLabel);
1312 void CFileItem::CleanString()
1314 if (IsLiveTV())
1315 return;
1317 std::string strLabel = GetLabel();
1318 std::string strTitle, strTitleAndYear, strYear;
1319 CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, true);
1320 SetLabel(strTitleAndYear);
1323 void CFileItem::SetLabel(const std::string &strLabel)
1325 if (strLabel == "..")
1327 m_bIsParentFolder = true;
1328 m_bIsFolder = true;
1329 m_specialSort = SortSpecialOnTop;
1330 SetLabelPreformatted(true);
1332 CGUIListItem::SetLabel(strLabel);
1335 void CFileItem::SetFileSizeLabel()
1337 if(m_bIsFolder && m_dwSize == 0)
1338 SetLabel2("");
1339 else
1340 SetLabel2(StringUtils::SizeToString(m_dwSize));
1343 bool CFileItem::CanQueue() const
1345 return m_bCanQueue;
1348 void CFileItem::SetCanQueue(bool bYesNo)
1350 m_bCanQueue = bYesNo;
1353 bool CFileItem::IsParentFolder() const
1355 return m_bIsParentFolder;
1358 void CFileItem::FillInMimeType(bool lookup /*= true*/)
1360 //! @todo adapt this to use CMime::GetMimeType()
1361 if (m_mimetype.empty())
1363 if (m_bIsFolder)
1364 m_mimetype = "x-directory/normal";
1365 else if (HasPVRChannelInfoTag())
1366 m_mimetype = GetPVRChannelInfoTag()->MimeType();
1367 else if (StringUtils::StartsWithNoCase(GetDynPath(), "shout://") ||
1368 StringUtils::StartsWithNoCase(GetDynPath(), "http://") ||
1369 StringUtils::StartsWithNoCase(GetDynPath(), "https://"))
1371 // If lookup is false, bail out early to leave mime type empty
1372 if (!lookup)
1373 return;
1375 CCurlFile::GetMimeType(GetDynURL(), m_mimetype);
1377 // try to get mime-type again but with an NSPlayer User-Agent
1378 // in order for server to provide correct mime-type. Allows us
1379 // to properly detect an MMS stream
1380 if (StringUtils::StartsWithNoCase(m_mimetype, "video/x-ms-"))
1381 CCurlFile::GetMimeType(GetDynURL(), m_mimetype, "NSPlayer/11.00.6001.7000");
1383 // make sure there are no options set in mime-type
1384 // mime-type can look like "video/x-ms-asf ; charset=utf8"
1385 size_t i = m_mimetype.find(';');
1386 if(i != std::string::npos)
1387 m_mimetype.erase(i, m_mimetype.length() - i);
1388 StringUtils::Trim(m_mimetype);
1390 else
1391 m_mimetype = CMime::GetMimeType(*this);
1393 // if it's still empty set to an unknown type
1394 if (m_mimetype.empty())
1395 m_mimetype = "application/octet-stream";
1398 // change protocol to mms for the following mime-type. Allows us to create proper FileMMS.
1399 if(StringUtils::StartsWithNoCase(m_mimetype, "application/vnd.ms.wms-hdr.asfv1") ||
1400 StringUtils::StartsWithNoCase(m_mimetype, "application/x-mms-framed"))
1402 if (m_strDynPath.empty())
1403 m_strDynPath = m_strPath;
1405 StringUtils::Replace(m_strDynPath, "http:", "mms:");
1409 void CFileItem::UpdateMimeType(bool lookup /*= true*/)
1411 //! @todo application/octet-stream might actually have been set by a web lookup. Currently we
1412 //! cannot distinguish between set as fallback only (see FillInMimeType) or as an actual value.
1413 if (m_mimetype == "application/octet-stream")
1414 m_mimetype.clear();
1416 FillInMimeType(lookup);
1419 void CFileItem::SetMimeTypeForInternetFile()
1421 if (m_doContentLookup && NETWORK::IsInternetStream(*this))
1423 SetMimeType("");
1424 FillInMimeType(true);
1428 bool CFileItem::IsSamePath(const CFileItem *item) const
1430 if (!item)
1431 return false;
1433 if (!m_strPath.empty() && item->GetPath() == m_strPath)
1435 if (item->HasProperty("item_start") || HasProperty("item_start"))
1436 return (item->GetProperty("item_start") == GetProperty("item_start"));
1437 // See if we have associated a bluray playlist
1438 if (VIDEO::IsBlurayPlaylist(*this) || VIDEO::IsBlurayPlaylist(*item))
1439 return (GetDynPath() == item->GetDynPath());
1440 return true;
1442 if (HasMusicInfoTag() && item->HasMusicInfoTag())
1444 if (GetMusicInfoTag()->GetDatabaseId() != -1 && item->GetMusicInfoTag()->GetDatabaseId() != -1)
1445 return ((GetMusicInfoTag()->GetDatabaseId() == item->GetMusicInfoTag()->GetDatabaseId()) &&
1446 (GetMusicInfoTag()->GetType() == item->GetMusicInfoTag()->GetType()));
1448 if (HasVideoInfoTag() && item->HasVideoInfoTag())
1450 const CVideoInfoTag* myTag{GetVideoInfoTag()};
1451 const CVideoInfoTag* otherTag{item->GetVideoInfoTag()};
1452 if (myTag->m_iDbId != -1 && otherTag->m_iDbId != -1)
1454 if ((myTag->m_iDbId == otherTag->m_iDbId) && (myTag->m_type == otherTag->m_type))
1456 // for movies with multiple versions, wie need also to check the file id
1457 if (HasVideoVersions() && item->HasVideoVersions() && myTag->m_iFileId != -1 &&
1458 otherTag->m_iFileId != -1)
1459 return myTag->m_iFileId == otherTag->m_iFileId;
1460 return true;
1464 if (MUSIC::IsMusicDb(*this) && HasMusicInfoTag())
1466 CFileItem dbItem(m_musicInfoTag->GetURL(), false);
1467 if (HasProperty("item_start"))
1468 dbItem.SetProperty("item_start", GetProperty("item_start"));
1469 return dbItem.IsSamePath(item);
1471 if (VIDEO::IsVideoDb(*this) && HasVideoInfoTag())
1473 CFileItem dbItem(GetVideoInfoTag()->m_strFileNameAndPath, false);
1474 if (HasProperty("item_start"))
1475 dbItem.SetProperty("item_start", GetProperty("item_start"));
1476 return dbItem.IsSamePath(item);
1478 if (MUSIC::IsMusicDb(*item) && item->HasMusicInfoTag())
1480 CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
1481 if (item->HasProperty("item_start"))
1482 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1483 return IsSamePath(&dbItem);
1485 if (VIDEO::IsVideoDb(*item) && item->HasVideoInfoTag())
1487 CFileItem dbItem(item->GetVideoInfoTag()->m_strFileNameAndPath, false);
1488 if (item->HasProperty("item_start"))
1489 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1490 return IsSamePath(&dbItem);
1492 if (HasProperty("original_listitem_url"))
1493 return (GetProperty("original_listitem_url") == item->GetPath());
1494 return false;
1497 bool CFileItem::IsAlbum() const
1499 return m_bIsAlbum;
1502 void CFileItem::UpdateInfo(const CFileItem &item, bool replaceLabels /*=true*/)
1504 if (item.HasVideoInfoTag())
1505 { // copy info across
1506 //! @todo premiered info is normally stored in m_dateTime by the db
1508 if (item.m_videoInfoTag)
1510 if (m_videoInfoTag)
1511 *m_videoInfoTag = *item.m_videoInfoTag;
1512 else
1513 m_videoInfoTag = new CVideoInfoTag(*item.m_videoInfoTag);
1515 else
1517 if (m_videoInfoTag)
1518 delete m_videoInfoTag;
1520 m_videoInfoTag = new CVideoInfoTag;
1523 m_pvrRecordingInfoTag = item.m_pvrRecordingInfoTag;
1525 SetOverlayImage(GetVideoInfoTag()->GetPlayCount() > 0 ? CGUIListItem::ICON_OVERLAY_WATCHED
1526 : CGUIListItem::ICON_OVERLAY_UNWATCHED);
1527 SetInvalid();
1529 if (item.HasMusicInfoTag())
1531 *GetMusicInfoTag() = *item.GetMusicInfoTag();
1532 SetInvalid();
1534 if (item.HasPictureInfoTag())
1536 *GetPictureInfoTag() = *item.GetPictureInfoTag();
1537 SetInvalid();
1539 if (item.HasGameInfoTag())
1541 *GetGameInfoTag() = *item.GetGameInfoTag();
1542 SetInvalid();
1544 if (item.HasPVRChannelGroupMemberInfoTag())
1546 m_pvrChannelGroupMemberInfoTag = item.GetPVRChannelGroupMemberInfoTag();
1547 SetInvalid();
1549 if (item.HasPVRTimerInfoTag())
1551 m_pvrTimerInfoTag = item.m_pvrTimerInfoTag;
1552 SetInvalid();
1554 if (item.HasEPGInfoTag())
1556 m_epgInfoTag = item.m_epgInfoTag;
1557 SetInvalid();
1559 if (item.HasEPGSearchFilter())
1561 m_epgSearchFilter = item.m_epgSearchFilter;
1562 SetInvalid();
1564 SetDynPath(item.GetDynPath());
1565 if (replaceLabels && !item.GetLabel().empty())
1566 SetLabel(item.GetLabel());
1567 if (replaceLabels && !item.GetLabel2().empty())
1568 SetLabel2(item.GetLabel2());
1569 if (!item.GetArt().empty())
1570 SetArt(item.GetArt());
1571 AppendProperties(item);
1573 SetContentLookup(item.m_doContentLookup);
1574 SetMimeType(item.m_mimetype);
1575 UpdateMimeType(m_doContentLookup);
1578 void CFileItem::MergeInfo(const CFileItem& item)
1580 // TODO: Currently merge the metadata/art info is implemented for video case only
1581 if (item.HasVideoInfoTag())
1583 if (item.m_videoInfoTag)
1585 if (m_videoInfoTag)
1586 m_videoInfoTag->Merge(*item.m_videoInfoTag);
1587 else
1588 m_videoInfoTag = new CVideoInfoTag(*item.m_videoInfoTag);
1591 m_pvrRecordingInfoTag = item.m_pvrRecordingInfoTag;
1593 SetOverlayImage(GetVideoInfoTag()->GetPlayCount() > 0 ? CGUIListItem::ICON_OVERLAY_WATCHED
1594 : CGUIListItem::ICON_OVERLAY_UNWATCHED);
1595 SetInvalid();
1597 if (item.HasMusicInfoTag())
1599 *GetMusicInfoTag() = *item.GetMusicInfoTag();
1600 SetInvalid();
1602 if (item.HasPictureInfoTag())
1604 *GetPictureInfoTag() = *item.GetPictureInfoTag();
1605 SetInvalid();
1607 if (item.HasGameInfoTag())
1609 *GetGameInfoTag() = *item.GetGameInfoTag();
1610 SetInvalid();
1612 if (item.HasPVRChannelGroupMemberInfoTag())
1614 m_pvrChannelGroupMemberInfoTag = item.GetPVRChannelGroupMemberInfoTag();
1615 SetInvalid();
1617 if (item.HasPVRTimerInfoTag())
1619 m_pvrTimerInfoTag = item.m_pvrTimerInfoTag;
1620 SetInvalid();
1622 if (item.HasEPGInfoTag())
1624 m_epgInfoTag = item.m_epgInfoTag;
1625 SetInvalid();
1627 if (item.HasEPGSearchFilter())
1629 m_epgSearchFilter = item.m_epgSearchFilter;
1630 SetInvalid();
1632 SetDynPath(item.GetDynPath());
1633 if (!item.GetLabel().empty())
1634 SetLabel(item.GetLabel());
1635 if (!item.GetLabel2().empty())
1636 SetLabel2(item.GetLabel2());
1637 if (!item.GetArt().empty())
1639 if (VIDEO::IsVideo(item))
1640 AppendArt(item.GetArt());
1641 else
1642 SetArt(item.GetArt());
1644 AppendProperties(item);
1646 SetContentLookup(item.m_doContentLookup);
1647 SetMimeType(item.m_mimetype);
1648 UpdateMimeType(m_doContentLookup);
1651 void CFileItem::SetFromVideoInfoTag(const CVideoInfoTag &video)
1653 if (!video.m_strTitle.empty())
1654 SetLabel(video.m_strTitle);
1655 if (video.m_strFileNameAndPath.empty())
1657 m_strPath = video.m_strPath;
1658 URIUtils::AddSlashAtEnd(m_strPath);
1659 m_bIsFolder = true;
1661 else
1663 m_strPath = video.m_strFileNameAndPath;
1664 m_bIsFolder = false;
1667 if (m_videoInfoTag)
1668 *m_videoInfoTag = video;
1669 else
1670 m_videoInfoTag = new CVideoInfoTag(video);
1672 if (video.m_iSeason == 0)
1673 SetProperty("isspecial", "true");
1674 FillInDefaultIcon();
1675 FillInMimeType(false);
1678 namespace
1680 class CPropertySaveHelper
1682 public:
1683 CPropertySaveHelper(CFileItem& item, const std::string& property, const std::string& value)
1684 : m_item(item), m_property(property), m_value(value)
1688 bool NeedsSave() const { return !m_value.empty() || m_item.HasProperty(m_property); }
1690 std::string GetValueToSave(const std::string& currentValue) const
1692 std::string value;
1694 if (!m_value.empty())
1696 // Overwrite whatever we have; remember what we had originally.
1697 if (!m_item.HasProperty(m_property))
1698 m_item.SetProperty(m_property, currentValue);
1700 value = m_value;
1702 else if (m_item.HasProperty(m_property))
1704 // Restore original value
1705 value = m_item.GetProperty(m_property).asString();
1706 m_item.ClearProperty(m_property);
1709 return value;
1712 private:
1713 CFileItem& m_item;
1714 const std::string m_property;
1715 const std::string m_value;
1717 } // unnamed namespace
1719 void CFileItem::SetFromMusicInfoTag(const MUSIC_INFO::CMusicInfoTag& music)
1721 const std::string path = GetPath();
1722 if (path.empty())
1724 SetPath(music.GetURL());
1726 else
1728 const CPropertySaveHelper dynpath(*this, "OriginalDynPath", music.GetURL());
1729 if (dynpath.NeedsSave())
1730 SetDynPath(dynpath.GetValueToSave(m_strDynPath));
1733 const CPropertySaveHelper label(*this, "OriginalLabel", music.GetTitle());
1734 if (label.NeedsSave())
1735 SetLabel(label.GetValueToSave(GetLabel()));
1737 const CPropertySaveHelper thumb(*this, "OriginalThumb", music.GetStationArt());
1738 if (thumb.NeedsSave())
1739 SetArt("thumb", thumb.GetValueToSave(GetArt("thumb")));
1741 *GetMusicInfoTag() = music;
1742 FillInDefaultIcon();
1743 FillInMimeType(false);
1746 void CFileItem::SetFromAlbum(const CAlbum &album)
1748 if (!album.strAlbum.empty())
1749 SetLabel(album.strAlbum);
1750 m_bIsFolder = true;
1751 m_strLabel2 = album.GetAlbumArtistString();
1752 GetMusicInfoTag()->SetAlbum(album);
1754 if (album.art.empty())
1755 SetArt("icon", "DefaultAlbumCover.png");
1756 else
1757 SetArt(album.art);
1759 m_bIsAlbum = true;
1760 CMusicDatabase::SetPropertiesFromAlbum(*this,album);
1761 FillInMimeType(false);
1764 void CFileItem::SetFromSong(const CSong &song)
1766 if (!song.strTitle.empty())
1767 SetLabel(song.strTitle);
1768 if (song.idSong > 0)
1770 std::string strExt = URIUtils::GetExtension(song.strFileName);
1771 m_strPath = StringUtils::Format("musicdb://songs/{}{}", song.idSong, strExt);
1773 else if (!song.strFileName.empty())
1774 m_strPath = song.strFileName;
1775 GetMusicInfoTag()->SetSong(song);
1776 m_lStartOffset = song.iStartOffset;
1777 m_lStartPartNumber = 1;
1778 SetProperty("item_start", song.iStartOffset);
1779 m_lEndOffset = song.iEndOffset;
1780 if (!song.strThumb.empty())
1781 SetArt("thumb", song.strThumb);
1782 FillInMimeType(false);
1786 * @todo Ideally this (and SetPath) would not be available outside of construction
1787 * for CFileItem objects, or at least restricted to essentially be equivalent
1788 * to construction. This would require re-formulating a bunch of CFileItem
1789 * construction, and also allowing CFileItemList to have its own (public)
1790 * SetURL() function, so for now we give direct access.
1792 void CFileItem::SetURL(const CURL& url)
1794 m_strPath = url.Get();
1797 const CURL CFileItem::GetURL() const
1799 CURL url(m_strPath);
1800 return url;
1803 bool CFileItem::IsURL(const CURL& url) const
1805 return IsPath(url.Get());
1808 bool CFileItem::IsPath(const std::string& path, bool ignoreURLOptions /* = false */) const
1810 return URIUtils::PathEquals(m_strPath, path, false, ignoreURLOptions);
1813 void CFileItem::SetDynURL(const CURL& url)
1815 m_strDynPath = url.Get();
1818 const CURL CFileItem::GetDynURL() const
1820 if (!m_strDynPath.empty())
1822 CURL url(m_strDynPath);
1823 return url;
1825 else
1827 CURL url(m_strPath);
1828 return url;
1832 const std::string &CFileItem::GetDynPath() const
1834 if (!m_strDynPath.empty())
1835 return m_strDynPath;
1836 else
1837 return m_strPath;
1840 void CFileItem::SetDynPath(const std::string &path)
1842 m_strDynPath = path;
1845 std::string CFileItem::GetBlurayPath() const
1847 if (VIDEO::IsBlurayPlaylist(*this))
1849 CURL url(GetDynPath());
1850 CURL url2(url.GetHostName()); // strip bluray://
1851 if (url2.IsProtocol("udf"))
1852 // ISO
1853 return url2.GetHostName(); // strip udf://
1854 else if (url.IsProtocol("bluray"))
1855 // BDMV
1856 return url2.Get() + "BDMV/index.bdmv";
1858 return GetDynPath();
1861 void CFileItem::SetCueDocument(const CCueDocumentPtr& cuePtr)
1863 m_cueDocument = cuePtr;
1866 void CFileItem::LoadEmbeddedCue()
1868 CMusicInfoTag& tag = *GetMusicInfoTag();
1869 if (!tag.Loaded())
1870 return;
1872 const std::string embeddedCue = tag.GetCueSheet();
1873 if (!embeddedCue.empty())
1875 CCueDocumentPtr cuesheet(new CCueDocument);
1876 if (cuesheet->ParseTag(embeddedCue))
1878 std::vector<std::string> MediaFileVec;
1879 cuesheet->GetMediaFiles(MediaFileVec);
1880 for (std::vector<std::string>::iterator itMedia = MediaFileVec.begin();
1881 itMedia != MediaFileVec.end(); ++itMedia)
1882 cuesheet->UpdateMediaFile(*itMedia, GetPath());
1883 SetCueDocument(cuesheet);
1885 // Clear cuesheet tag having added it to item
1886 tag.SetCueSheet("");
1890 bool CFileItem::HasCueDocument() const
1892 return (m_cueDocument.get() != nullptr);
1895 bool CFileItem::LoadTracksFromCueDocument(CFileItemList& scannedItems)
1897 if (!m_cueDocument)
1898 return false;
1900 bool result = m_cueDocument->LoadTracks(scannedItems, *this);
1901 m_cueDocument.reset();
1903 return result;
1906 std::string CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */, bool fallbackToFolder /* = false */) const
1908 if (m_strPath.empty() || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://") ||
1909 StringUtils::StartsWithNoCase(m_strPath, "newplaylist://") || m_bIsShareOrDrive ||
1910 NETWORK::IsInternetStream(*this) || URIUtils::IsUPnP(m_strPath) ||
1911 (URIUtils::IsFTP(m_strPath) &&
1912 !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs) ||
1913 IsPlugin() || IsAddonsPath() || IsLibraryFolder() || IsParentFolder() ||
1914 MUSIC::IsMusicDb(*this))
1915 return "";
1917 // we first check for <filename>.tbn or <foldername>.tbn
1918 std::string fileThumb(ART::GetTBNFile(*this));
1919 if (CFile::Exists(fileThumb))
1920 return fileThumb;
1922 // Fall back to folder thumb, if requested
1923 if (!m_bIsFolder && fallbackToFolder)
1925 CFileItem item(URIUtils::GetDirectory(m_strPath), true);
1926 return item.GetUserMusicThumb(alwaysCheckRemote);
1929 // if a folder, check for folder.jpg
1930 if (m_bIsFolder && !IsFileFolder() &&
1931 (!NETWORK::IsRemote(*this) || alwaysCheckRemote ||
1932 CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
1933 CSettings::SETTING_MUSICFILES_FINDREMOTETHUMBS)))
1935 std::vector<CVariant> thumbs = CServiceBroker::GetSettingsComponent()->GetSettings()->GetList(
1936 CSettings::SETTING_MUSICLIBRARY_MUSICTHUMBS);
1937 for (const auto& i : thumbs)
1939 std::string strFileName = i.asString();
1940 std::string folderThumb(GetFolderThumb(strFileName));
1941 if (CFile::Exists(folderThumb)) // folder.jpg
1942 return folderThumb;
1943 size_t period = strFileName.find_last_of('.');
1944 if (period != std::string::npos)
1946 std::string ext;
1947 std::string name = strFileName;
1948 std::string folderThumb1 = folderThumb;
1949 name.erase(period);
1950 ext = strFileName.substr(period);
1951 StringUtils::ToUpper(ext);
1952 StringUtils::Replace(folderThumb1, strFileName, name + ext);
1953 if (CFile::Exists(folderThumb1)) // folder.JPG
1954 return folderThumb1;
1956 folderThumb1 = folderThumb;
1957 std::string firstletter = name.substr(0, 1);
1958 StringUtils::ToUpper(firstletter);
1959 name.replace(0, 1, firstletter);
1960 StringUtils::Replace(folderThumb1, strFileName, name + ext);
1961 if (CFile::Exists(folderThumb1)) // Folder.JPG
1962 return folderThumb1;
1964 folderThumb1 = folderThumb;
1965 StringUtils::ToLower(ext);
1966 StringUtils::Replace(folderThumb1, strFileName, name + ext);
1967 if (CFile::Exists(folderThumb1)) // Folder.jpg
1968 return folderThumb1;
1972 // No thumb found
1973 return "";
1976 bool CFileItem::SkipLocalArt() const
1978 return (m_strPath.empty() || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://") ||
1979 StringUtils::StartsWithNoCase(m_strPath, "newplaylist://") || m_bIsShareOrDrive ||
1980 NETWORK::IsInternetStream(*this) || URIUtils::IsUPnP(m_strPath) ||
1981 (URIUtils::IsFTP(m_strPath) &&
1982 !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs) ||
1983 IsPlugin() || IsAddonsPath() || IsLibraryFolder() || IsParentFolder() || IsLiveTV() ||
1984 IsPVRRecording() || IsDVD());
1987 std::string CFileItem::GetThumbHideIfUnwatched(const CFileItem* item) const
1989 const std::shared_ptr<CSettingList> setting(std::dynamic_pointer_cast<CSettingList>(
1990 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(
1991 CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS)));
1992 if (setting && item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_type == MediaTypeEpisode &&
1993 item->GetVideoInfoTag()->GetPlayCount() == 0 &&
1994 !CSettingUtils::FindIntInList(setting,
1995 CSettings::VIDEOLIBRARY_THUMB_SHOW_UNWATCHED_EPISODE) &&
1996 item->HasArt("thumb"))
1998 std::string fanArt = item->GetArt("fanart");
1999 if (fanArt.empty())
2000 return "OverlaySpoiler.png";
2001 else
2002 return fanArt;
2005 return item->GetArt("thumb");
2008 std::string CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) const
2010 if (SkipLocalArt())
2011 return "";
2013 std::string thumb;
2014 if (!m_bIsFolder)
2016 thumb = GetLocalArt(artFile, false);
2017 if (!thumb.empty() && CFile::Exists(thumb))
2018 return thumb;
2020 if ((useFolder || (m_bIsFolder && !IsFileFolder())) && !artFile.empty())
2022 std::string thumb2 = GetLocalArt(artFile, true);
2023 if (!thumb2.empty() && thumb2 != thumb && CFile::Exists(thumb2))
2024 return thumb2;
2026 return "";
2029 std::string CFileItem::GetLocalArtBaseFilename() const
2031 bool useFolder = false;
2032 return GetLocalArtBaseFilename(useFolder);
2035 std::string CFileItem::GetLocalArtBaseFilename(bool& useFolder) const
2037 std::string strFile;
2038 if (IsStack())
2040 std::string strPath;
2041 URIUtils::GetParentPath(m_strPath,strPath);
2042 strFile = URIUtils::AddFileToFolder(
2043 strPath, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(m_strPath)));
2046 std::string file = strFile.empty() ? m_strPath : strFile;
2047 if (URIUtils::IsInRAR(file) || URIUtils::IsInZIP(file))
2049 std::string strPath = URIUtils::GetDirectory(file);
2050 std::string strParent;
2051 URIUtils::GetParentPath(strPath,strParent);
2052 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(file));
2055 if (IsMultiPath())
2056 strFile = CMultiPathDirectory::GetFirstPath(m_strPath);
2058 if (IsOpticalMediaFile())
2059 { // optical media files should be treated like folders
2060 useFolder = true;
2061 strFile = GetLocalMetadataPath();
2063 else if (useFolder && !(m_bIsFolder && !IsFileFolder()))
2065 file = strFile.empty() ? m_strPath : strFile;
2066 strFile = URIUtils::GetDirectory(file);
2069 if (strFile.empty())
2070 strFile = GetDynPath();
2072 return strFile;
2075 std::string CFileItem::GetLocalArt(const std::string& artFile, bool useFolder) const
2077 // no retrieving of empty art files from folders
2078 if (useFolder && artFile.empty())
2079 return "";
2081 std::string strFile = GetLocalArtBaseFilename(useFolder);
2082 if (strFile.empty()) // empty filepath -> nothing to find
2083 return "";
2085 if (useFolder)
2087 if (!artFile.empty())
2088 return URIUtils::AddFileToFolder(strFile, artFile);
2090 else
2092 if (artFile.empty()) // old thumbnail matching
2093 return URIUtils::ReplaceExtension(strFile, ".tbn");
2094 else
2095 return URIUtils::ReplaceExtension(strFile, "-" + artFile);
2097 return "";
2100 std::string CFileItem::GetFolderThumb(const std::string &folderJPG /* = "folder.jpg" */) const
2102 std::string strFolder = m_strPath;
2104 if (IsStack() ||
2105 URIUtils::IsInRAR(strFolder) ||
2106 URIUtils::IsInZIP(strFolder))
2108 URIUtils::GetParentPath(m_strPath,strFolder);
2111 if (IsMultiPath())
2112 strFolder = CMultiPathDirectory::GetFirstPath(m_strPath);
2114 if (IsPlugin())
2115 return "";
2117 return URIUtils::AddFileToFolder(strFolder, folderJPG);
2120 std::string CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const
2122 if (IsPlugin() && HasVideoInfoTag() && !GetVideoInfoTag()->m_strTitle.empty())
2123 return GetVideoInfoTag()->m_strTitle;
2125 if (IsLabelPreformatted())
2126 return GetLabel();
2128 if (m_pvrRecordingInfoTag)
2129 return m_pvrRecordingInfoTag->m_strTitle;
2130 else if (URIUtils::IsPVRRecording(m_strPath))
2132 std::string title = CPVRRecording::GetTitleFromURL(m_strPath);
2133 if (!title.empty())
2134 return title;
2137 std::string strMovieName;
2138 if (URIUtils::IsStack(m_strPath))
2139 strMovieName = CStackDirectory::GetStackedTitlePath(m_strPath);
2140 else
2141 strMovieName = GetBaseMoviePath(bUseFolderNames);
2143 URIUtils::RemoveSlashAtEnd(strMovieName);
2145 return CURL::Decode(URIUtils::GetFileName(strMovieName));
2148 std::string CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
2150 std::string strMovieName = m_strPath;
2152 if (IsMultiPath())
2153 strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
2155 if (IsOpticalMediaFile())
2156 return GetLocalMetadataPath();
2158 if (bUseFolderNames &&
2159 (!m_bIsFolder || URIUtils::IsInArchive(m_strPath) ||
2160 (HasVideoInfoTag() && GetVideoInfoTag()->m_iDbId > 0 && !CMediaTypes::IsContainer(GetVideoInfoTag()->m_type))))
2162 std::string name2(strMovieName);
2163 URIUtils::GetParentPath(name2,strMovieName);
2164 if (URIUtils::IsInArchive(m_strPath))
2166 // Try to get archive itself, if empty take path before
2167 name2 = CURL(m_strPath).GetHostName();
2168 if (name2.empty())
2169 name2 = strMovieName;
2171 URIUtils::GetParentPath(name2, strMovieName);
2174 // Remove trailing 'Disc n' path segment to get actual movie title
2175 strMovieName = CUtil::RemoveTrailingDiscNumberSegmentFromPath(strMovieName);
2178 return strMovieName;
2181 std::string CFileItem::GetLocalMetadataPath() const
2183 if (m_bIsFolder && !IsFileFolder())
2184 return m_strPath;
2186 std::string parent{};
2187 if (VIDEO::IsBlurayPlaylist(*this))
2188 parent = URIUtils::GetParentPath(GetBlurayPath());
2189 else
2190 parent = URIUtils::GetParentPath(m_strPath);
2191 std::string parentFolder(parent);
2192 URIUtils::RemoveSlashAtEnd(parentFolder);
2193 parentFolder = URIUtils::GetFileName(parentFolder);
2194 if (StringUtils::EqualsNoCase(parentFolder, "VIDEO_TS") || StringUtils::EqualsNoCase(parentFolder, "BDMV"))
2195 { // go back up another one
2196 parent = URIUtils::GetParentPath(parent);
2198 return parent;
2201 bool CFileItem::LoadMusicTag()
2203 // not audio
2204 if (!MUSIC::IsAudio(*this))
2205 return false;
2206 // already loaded?
2207 if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
2208 return true;
2209 // check db
2210 CMusicDatabase musicDatabase;
2211 if (musicDatabase.Open())
2213 CSong song;
2214 if (musicDatabase.GetSongByFileName(m_strPath, song))
2216 GetMusicInfoTag()->SetSong(song);
2217 return true;
2219 musicDatabase.Close();
2221 // load tag from file
2222 CLog::Log(LOGDEBUG, "{}: loading tag information for file: {}", __FUNCTION__, m_strPath);
2223 CMusicInfoTagLoaderFactory factory;
2224 std::unique_ptr<IMusicInfoTagLoader> pLoader (factory.CreateLoader(*this));
2225 if (pLoader)
2227 if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
2228 return true;
2230 // no tag - try some other things
2231 if (MUSIC::IsCDDA(*this))
2233 // we have the tracknumber...
2234 int iTrack = GetMusicInfoTag()->GetTrackNumber();
2235 if (iTrack >= 1)
2237 std::string strText = g_localizeStrings.Get(554); // "Track"
2238 if (!strText.empty() && strText[strText.size() - 1] != ' ')
2239 strText += " ";
2240 std::string strTrack = StringUtils::Format((strText + "{}"), iTrack);
2241 GetMusicInfoTag()->SetTitle(strTrack);
2242 GetMusicInfoTag()->SetLoaded(true);
2243 return true;
2246 else
2248 std::string fileName = URIUtils::GetFileName(m_strPath);
2249 URIUtils::RemoveExtension(fileName);
2250 for (const std::string& fileFilter : CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicTagsFromFileFilters)
2252 CLabelFormatter formatter(fileFilter, "");
2253 if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
2255 GetMusicInfoTag()->SetLoaded(true);
2256 return true;
2260 return false;
2263 bool CFileItem::LoadGameTag()
2265 // Already loaded?
2266 if (HasGameInfoTag() && m_gameInfoTag->IsLoaded())
2267 return true;
2269 //! @todo
2270 GetGameInfoTag();
2272 m_gameInfoTag->SetLoaded(true);
2274 return false;
2277 bool CFileItem::LoadDetails()
2279 if (VIDEO::IsVideoDb(*this))
2281 if (HasVideoInfoTag())
2282 return true;
2284 CVideoDatabase db;
2285 if (!db.Open())
2287 CLog::LogF(LOGERROR, "Error opening video database");
2288 return false;
2291 VIDEODATABASEDIRECTORY::CQueryParams params;
2292 VIDEODATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(GetPath(), params);
2294 bool ret{false};
2295 auto tag{std::make_unique<CVideoInfoTag>()};
2296 if (params.GetMovieId() >= 0)
2297 ret = db.GetMovieInfo({}, *tag, static_cast<int>(params.GetMovieId()),
2298 static_cast<int>(params.GetVideoVersionId()));
2299 else if (params.GetMVideoId() >= 0)
2300 ret = db.GetMusicVideoInfo({}, *tag, static_cast<int>(params.GetMVideoId()));
2301 else if (params.GetEpisodeId() >= 0)
2302 ret = db.GetEpisodeInfo({}, *tag, static_cast<int>(params.GetEpisodeId()));
2303 else if (params.GetSetId() >= 0) // movie set
2304 ret = db.GetSetInfo(static_cast<int>(params.GetSetId()), *tag, this);
2305 else if (params.GetTvShowId() >= 0)
2307 if (params.GetSeason() >= 0)
2309 const int idSeason = db.GetSeasonId(static_cast<int>(params.GetTvShowId()),
2310 static_cast<int>(params.GetSeason()));
2311 if (idSeason >= 0)
2312 ret = db.GetSeasonInfo(idSeason, *tag, this);
2314 else
2315 ret = db.GetTvShowInfo({}, *tag, static_cast<int>(params.GetTvShowId()), this);
2318 if (ret)
2320 const CFileItem loadedItem{*tag};
2321 UpdateInfo(loadedItem);
2323 return ret;
2326 if (IsPVR())
2328 const std::shared_ptr<CFileItem> loadedItem{
2329 CServiceBroker::GetPVRManager().Get<PVR::GUI::Utils>().LoadItem(*this)};
2330 if (loadedItem)
2332 UpdateInfo(*loadedItem);
2333 return true;
2335 CLog::LogF(LOGERROR, "Error filling PVR item details (path={})", GetPath());
2336 return false;
2339 if (!PLAYLIST::IsPlayList(*this) && VIDEO::IsVideo(*this))
2341 if (HasVideoInfoTag())
2342 return true;
2344 CVideoDatabase db;
2345 if (!db.Open())
2347 CLog::LogF(LOGERROR, "Error opening video database");
2348 return false;
2351 auto tag{std::make_unique<CVideoInfoTag>()};
2352 if (db.LoadVideoInfo(GetDynPath(), *tag))
2354 const CFileItem loadedItem{*tag};
2355 UpdateInfo(loadedItem);
2356 return true;
2359 CLog::LogF(LOGERROR, "Error filling item details (path={})", GetPath());
2360 return false;
2363 if (PLAYLIST::IsPlayList(*this) && IsType(".strm"))
2365 const std::unique_ptr<PLAYLIST::CPlayList> playlist(PLAYLIST::CPlayListFactory::Create(*this));
2366 if (playlist)
2368 if (playlist->Load(GetPath()) && playlist->size() == 1)
2370 const auto item{(*playlist)[0]};
2371 if (VIDEO::IsVideo(*item))
2373 CVideoDatabase db;
2374 if (!db.Open())
2376 CLog::LogF(LOGERROR, "Error opening video database");
2377 return false;
2380 CVideoInfoTag tag;
2381 if (db.LoadVideoInfo(GetDynPath(), tag))
2383 UpdateInfo(*item);
2384 *GetVideoInfoTag() = tag;
2385 return true;
2388 else if (MUSIC::IsAudio(*item))
2390 if (item->LoadMusicTag())
2392 UpdateInfo(*item);
2393 return true;
2398 CLog::LogF(LOGERROR, "Error loading strm file details (path={})", GetPath());
2399 return false;
2402 if (MUSIC::IsAudio(*this))
2404 return LoadMusicTag();
2407 if (MUSIC::IsMusicDb(*this))
2409 if (HasMusicInfoTag())
2410 return true;
2412 CMusicDatabase db;
2413 if (!db.Open())
2415 CLog::LogF(LOGERROR, "Error opening music database");
2416 return false;
2419 MUSICDATABASEDIRECTORY::CQueryParams params;
2420 MUSICDATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(GetPath(), params);
2422 if (params.GetSongId() >= 0)
2424 CSong song;
2425 if (db.GetSong(params.GetSongId(), song))
2427 GetMusicInfoTag()->SetSong(song);
2428 return true;
2431 else if (params.GetAlbumId() >= 0)
2433 m_bIsFolder = true;
2434 CAlbum album;
2435 if (db.GetAlbum(params.GetAlbumId(), album, false))
2437 GetMusicInfoTag()->SetAlbum(album);
2438 return true;
2441 else if (params.GetArtistId() >= 0)
2443 m_bIsFolder = true;
2444 CArtist artist;
2445 if (db.GetArtist(params.GetArtistId(), artist, false))
2447 GetMusicInfoTag()->SetArtist(artist);
2448 return true;
2451 return false;
2454 //! @todo add support for other types on demand.
2455 CLog::LogF(LOGDEBUG, "Unsupported item type (path={})", GetPath());
2456 return false;
2459 bool CFileItem::HasVideoInfoTag() const
2461 // Note: CPVRRecording is derived from CVideoInfoTag
2462 return m_pvrRecordingInfoTag.get() != nullptr || m_videoInfoTag != nullptr;
2465 CVideoInfoTag* CFileItem::GetVideoInfoTag()
2467 // Note: CPVRRecording is derived from CVideoInfoTag
2468 if (m_pvrRecordingInfoTag)
2469 return m_pvrRecordingInfoTag.get();
2470 else if (!m_videoInfoTag)
2471 m_videoInfoTag = new CVideoInfoTag;
2473 return m_videoInfoTag;
2476 const CVideoInfoTag* CFileItem::GetVideoInfoTag() const
2478 // Note: CPVRRecording is derived from CVideoInfoTag
2479 return m_pvrRecordingInfoTag ? m_pvrRecordingInfoTag.get() : m_videoInfoTag;
2482 CPictureInfoTag* CFileItem::GetPictureInfoTag()
2484 if (!m_pictureInfoTag)
2485 m_pictureInfoTag = new CPictureInfoTag;
2487 return m_pictureInfoTag;
2490 MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
2492 if (!m_musicInfoTag)
2493 m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
2495 return m_musicInfoTag;
2498 CGameInfoTag* CFileItem::GetGameInfoTag()
2500 if (!m_gameInfoTag)
2501 m_gameInfoTag = new CGameInfoTag;
2503 return m_gameInfoTag;
2506 bool CFileItem::HasPVRChannelInfoTag() const
2508 return m_pvrChannelGroupMemberInfoTag && m_pvrChannelGroupMemberInfoTag->Channel() != nullptr;
2511 const std::shared_ptr<PVR::CPVRChannel> CFileItem::GetPVRChannelInfoTag() const
2513 return m_pvrChannelGroupMemberInfoTag ? m_pvrChannelGroupMemberInfoTag->Channel()
2514 : std::shared_ptr<CPVRChannel>();
2517 std::string CFileItem::FindTrailer() const
2519 std::string strFile2;
2520 std::string strFile = m_strPath;
2521 if (IsStack())
2523 std::string strPath;
2524 URIUtils::GetParentPath(m_strPath,strPath);
2525 CStackDirectory dir;
2526 std::string strPath2;
2527 strPath2 = dir.GetStackedTitlePath(strFile);
2528 strFile = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2));
2529 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
2530 std::string strTBNFile(URIUtils::ReplaceExtension(ART::GetTBNFile(item), "-trailer"));
2531 strFile2 = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile));
2533 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2535 std::string strPath = URIUtils::GetDirectory(strFile);
2536 std::string strParent;
2537 URIUtils::GetParentPath(strPath,strParent);
2538 strFile = URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath));
2541 // no local trailer available for these
2542 if (NETWORK::IsInternetStream(*this) || URIUtils::IsUPnP(strFile) ||
2543 URIUtils::IsBluray(strFile) || IsLiveTV() || IsPlugin() || IsDVD())
2544 return "";
2546 std::string strDir = URIUtils::GetDirectory(strFile);
2547 CFileItemList items;
2548 CDirectory::GetDirectory(strDir, items, CServiceBroker::GetFileExtensionProvider().GetVideoExtensions(), DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO | DIR_FLAG_NO_FILE_DIRS);
2549 URIUtils::RemoveExtension(strFile);
2550 strFile += "-trailer";
2551 std::string strFile3 = URIUtils::AddFileToFolder(strDir, "movie-trailer");
2553 // Precompile our REs
2554 VECCREGEXP matchRegExps;
2555 CRegExp tmpRegExp(true, CRegExp::autoUtf8);
2556 const std::vector<std::string>& strMatchRegExps = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_trailerMatchRegExps;
2558 std::vector<std::string>::const_iterator strRegExp = strMatchRegExps.begin();
2559 while (strRegExp != strMatchRegExps.end())
2561 if (tmpRegExp.RegComp(*strRegExp))
2563 matchRegExps.push_back(tmpRegExp);
2565 ++strRegExp;
2568 std::string strTrailer;
2569 for (int i = 0; i < items.Size(); i++)
2571 std::string strCandidate = items[i]->m_strPath;
2572 URIUtils::RemoveExtension(strCandidate);
2573 if (StringUtils::EqualsNoCase(strCandidate, strFile) ||
2574 StringUtils::EqualsNoCase(strCandidate, strFile2) ||
2575 StringUtils::EqualsNoCase(strCandidate, strFile3))
2577 strTrailer = items[i]->m_strPath;
2578 break;
2580 else
2582 VECCREGEXP::iterator expr = matchRegExps.begin();
2584 while (expr != matchRegExps.end())
2586 if (expr->RegFind(strCandidate) != -1)
2588 strTrailer = items[i]->m_strPath;
2589 i = items.Size();
2590 break;
2592 ++expr;
2597 return strTrailer;
2600 VideoDbContentType CFileItem::GetVideoContentType() const
2602 VideoDbContentType type = VideoDbContentType::MOVIES;
2603 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type == MediaTypeTvShow)
2604 type = VideoDbContentType::TVSHOWS;
2605 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type == MediaTypeEpisode)
2606 return VideoDbContentType::EPISODES;
2607 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type == MediaTypeMusicVideo)
2608 return VideoDbContentType::MUSICVIDEOS;
2609 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type == MediaTypeAlbum)
2610 return VideoDbContentType::MUSICALBUMS;
2612 CVideoDatabaseDirectory dir;
2613 VIDEODATABASEDIRECTORY::CQueryParams params;
2614 dir.GetQueryParams(m_strPath, params);
2615 if (params.GetSetId() != -1 && params.GetMovieId() == -1) // movie set
2616 return VideoDbContentType::MOVIE_SETS;
2618 return type;
2621 CFileItem CFileItem::GetItemToPlay() const
2623 if (HasEPGInfoTag())
2625 const std::shared_ptr<CPVRChannelGroupMember> groupMember =
2626 CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(*this);
2627 if (groupMember)
2628 return CFileItem(groupMember);
2630 return *this;
2633 CBookmark CFileItem::GetResumePoint() const
2635 if (HasVideoInfoTag())
2636 return GetVideoInfoTag()->GetResumePoint();
2637 return CBookmark();
2640 bool CFileItem::IsResumePointSet() const
2642 return GetResumePoint().IsSet();
2645 double CFileItem::GetCurrentResumeTime() const
2647 return lrint(GetResumePoint().timeInSeconds);
2650 bool CFileItem::GetCurrentResumeTimeAndPartNumber(int64_t& startOffset, int& partNumber) const
2652 CBookmark resumePoint(GetResumePoint());
2653 if (resumePoint.IsSet())
2655 startOffset = llrint(resumePoint.timeInSeconds);
2656 partNumber = resumePoint.partNumber;
2657 return true;
2659 return false;
2662 bool CFileItem::IsResumable() const
2664 if (m_bIsFolder)
2666 int64_t watched = 0;
2667 int64_t inprogress = 0;
2668 int64_t total = 0;
2669 if (HasProperty("inprogressepisodes"))
2671 // show/season
2672 watched = GetProperty("watchedepisodes").asInteger();
2673 inprogress = GetProperty("inprogressepisodes").asInteger();
2674 total = GetProperty("totalepisodes").asInteger();
2676 else if (HasProperty("inprogress"))
2678 // movie set
2679 watched = GetProperty("watched").asInteger();
2680 inprogress = GetProperty("inprogress").asInteger();
2681 total = GetProperty("total").asInteger();
2684 return ((total != watched) && (inprogress > 0 || watched != 0));
2686 else
2688 return HasVideoInfoTag() && GetVideoInfoTag()->GetResumePoint().IsPartWay();
2692 bool CFileItem::HasVideoVersions() const
2694 if (HasVideoInfoTag())
2696 return GetVideoInfoTag()->HasVideoVersions();
2698 return false;
2701 bool CFileItem::HasVideoExtras() const
2703 if (HasVideoInfoTag())
2705 return GetVideoInfoTag()->HasVideoExtras();
2707 return false;