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.
11 #include "CueDocument.h"
12 #include "ServiceBroker.h"
15 #include "events/IEvent.h"
16 #include "filesystem/CurlFile.h"
17 #include "filesystem/Directory.h"
18 #include "filesystem/File.h"
19 #include "filesystem/MultiPathDirectory.h"
20 #include "filesystem/MusicDatabaseDirectory.h"
21 #include "filesystem/StackDirectory.h"
22 #include "filesystem/VideoDatabaseDirectory.h"
23 #include "filesystem/VideoDatabaseDirectory/QueryParams.h"
24 #include "games/GameUtils.h"
25 #include "games/tags/GameInfoTag.h"
26 #include "guilib/LocalizeStrings.h"
27 #include "media/MediaLockState.h"
28 #include "music/Album.h"
29 #include "music/Artist.h"
30 #include "music/MusicDatabase.h"
31 #include "music/tags/MusicInfoTag.h"
32 #include "music/tags/MusicInfoTagLoaderFactory.h"
33 #include "pictures/PictureInfoTag.h"
34 #include "playlists/PlayListFactory.h"
35 #include "pvr/PVRManager.h"
36 #include "pvr/channels/PVRChannel.h"
37 #include "pvr/channels/PVRChannelGroupMember.h"
38 #include "pvr/epg/EpgInfoTag.h"
39 #include "pvr/epg/EpgSearchFilter.h"
40 #include "pvr/guilib/PVRGUIActionsChannels.h"
41 #include "pvr/recordings/PVRRecording.h"
42 #include "pvr/timers/PVRTimerInfoTag.h"
43 #include "settings/AdvancedSettings.h"
44 #include "settings/SettingUtils.h"
45 #include "settings/Settings.h"
46 #include "settings/SettingsComponent.h"
47 #include "settings/lib/Setting.h"
48 #include "utils/Archive.h"
49 #include "utils/Crc32.h"
50 #include "utils/FileExtensionProvider.h"
51 #include "utils/Mime.h"
52 #include "utils/Random.h"
53 #include "utils/RegExp.h"
54 #include "utils/StringUtils.h"
55 #include "utils/URIUtils.h"
56 #include "utils/Variant.h"
57 #include "utils/log.h"
58 #include "video/Bookmark.h"
59 #include "video/VideoDatabase.h"
60 #include "video/VideoInfoTag.h"
67 using namespace XFILE
;
68 using namespace PLAYLIST
;
69 using namespace MUSIC_INFO
;
73 CFileItem::CFileItem(const CSong
& song
)
79 CFileItem::CFileItem(const CSong
& song
, const CMusicInfoTag
& music
)
83 *GetMusicInfoTag() = music
;
86 CFileItem::CFileItem(const CURL
&url
, const CAlbum
& album
)
90 m_strPath
= url
.Get();
91 URIUtils::AddSlashAtEnd(m_strPath
);
95 CFileItem::CFileItem(const std::string
&path
, const CAlbum
& album
)
100 URIUtils::AddSlashAtEnd(m_strPath
);
104 CFileItem::CFileItem(const CMusicInfoTag
& music
)
107 SetLabel(music
.GetTitle());
108 m_strPath
= music
.GetURL();
109 m_bIsFolder
= URIUtils::HasSlashAtEnd(m_strPath
);
110 *GetMusicInfoTag() = music
;
112 FillInMimeType(false);
115 CFileItem::CFileItem(const CVideoInfoTag
& movie
)
118 SetFromVideoInfoTag(movie
);
123 std::string
GetEpgTagTitle(const std::shared_ptr
<CPVREpgInfoTag
>& epgTag
)
125 if (CServiceBroker::GetPVRManager().IsParentalLocked(epgTag
))
126 return g_localizeStrings
.Get(19266); // Parental locked
127 else if (epgTag
->Title().empty() &&
128 !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_HIDENOINFOAVAILABLE
))
129 return g_localizeStrings
.Get(19055); // no information available
131 return epgTag
->Title();
133 } // unnamed namespace
135 void CFileItem::FillMusicInfoTag(const std::shared_ptr
<CPVREpgInfoTag
>& tag
)
137 CMusicInfoTag
* musictag
= GetMusicInfoTag(); // create (!) the music tag.
141 musictag
->SetTitle(GetEpgTagTitle(tag
));
142 musictag
->SetGenre(tag
->Genre());
143 musictag
->SetDuration(tag
->GetDuration());
144 musictag
->SetURL(tag
->Path());
146 else if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
147 CSettings::SETTING_EPG_HIDENOINFOAVAILABLE
))
149 musictag
->SetTitle(g_localizeStrings
.Get(19055)); // no information available
152 musictag
->SetLoaded(true);
155 CFileItem::CFileItem(const std::shared_ptr
<CPVREpgInfoTag
>& tag
)
161 m_strPath
= tag
->Path();
163 SetLabel(GetEpgTagTitle(tag
));
164 m_dateTime
= tag
->StartAsLocalTime();
166 if (!tag
->IconPath().empty())
168 SetArt("icon", tag
->IconPath());
172 const std::string iconPath
= tag
->ChannelIconPath();
173 if (!iconPath
.empty())
174 SetArt("icon", iconPath
);
175 else if (tag
->IsRadio())
176 SetArt("icon", "DefaultMusicSongs.png");
178 SetArt("icon", "DefaultTVShows.png");
181 // Speedup FillInDefaultIcon()
182 SetProperty("icon_never_overlay", true);
184 if (tag
->IsRadio() && !HasMusicInfoTag())
185 FillMusicInfoTag(tag
);
187 FillInMimeType(false);
190 CFileItem::CFileItem(const std::shared_ptr
<PVR::CPVREpgSearchFilter
>& filter
)
195 m_epgSearchFilter
= filter
;
196 m_strPath
= filter
->GetPath();
198 SetLabel(filter
->GetTitle());
200 const CDateTime lastExec
= filter
->GetLastExecutedDateTime();
201 if (lastExec
.IsValid())
202 m_dateTime
.SetFromUTCDateTime(lastExec
);
204 SetArt("icon", "DefaultPVRSearch.png");
206 // Speedup FillInDefaultIcon()
207 SetProperty("icon_never_overlay", true);
209 FillInMimeType(false);
212 CFileItem::CFileItem(const std::shared_ptr
<CPVRChannelGroupMember
>& channelGroupMember
)
216 const std::shared_ptr
<CPVRChannel
> channel
= channelGroupMember
->Channel();
218 m_pvrChannelGroupMemberInfoTag
= channelGroupMember
;
220 m_strPath
= channelGroupMember
->Path();
223 SetLabel(channel
->ChannelName());
225 if (!channel
->IconPath().empty())
226 SetArt("icon", channel
->IconPath());
227 else if (channel
->IsRadio())
228 SetArt("icon", "DefaultMusicSongs.png");
230 SetArt("icon", "DefaultTVShows.png");
232 SetProperty("channelid", channel
->ChannelID());
233 SetProperty("path", channelGroupMember
->Path());
234 SetArt("thumb", channel
->IconPath());
236 // Speedup FillInDefaultIcon()
237 SetProperty("icon_never_overlay", true);
239 if (channel
->IsRadio() && !HasMusicInfoTag())
241 const std::shared_ptr
<CPVREpgInfoTag
> epgNow
= channel
->GetEPGNow();
242 FillMusicInfoTag(epgNow
);
244 FillInMimeType(false);
247 CFileItem::CFileItem(const std::shared_ptr
<CPVRRecording
>& record
)
252 m_pvrRecordingInfoTag
= record
;
253 m_strPath
= record
->m_strFileNameAndPath
;
254 SetLabel(record
->m_strTitle
);
255 m_dateTime
= record
->RecordingTimeAsLocalTime();
256 m_dwSize
= record
->GetSizeInBytes();
260 if (!record
->IconPath().empty())
261 SetArt("icon", record
->IconPath());
264 const std::shared_ptr
<CPVRChannel
> channel
= record
->Channel();
265 if (channel
&& !channel
->IconPath().empty())
266 SetArt("icon", channel
->IconPath());
267 else if (record
->IsRadio())
268 SetArt("icon", "DefaultMusicSongs.png");
270 SetArt("icon", "DefaultTVShows.png");
273 if (!record
->ThumbnailPath().empty())
274 SetArt("thumb", record
->ThumbnailPath());
276 if (!record
->FanartPath().empty())
277 SetArt("fanart", record
->FanartPath());
279 // Speedup FillInDefaultIcon()
280 SetProperty("icon_never_overlay", true);
282 FillInMimeType(false);
285 CFileItem::CFileItem(const std::shared_ptr
<CPVRTimerInfoTag
>& timer
)
289 m_bIsFolder
= timer
->IsTimerRule();
290 m_pvrTimerInfoTag
= timer
;
291 m_strPath
= timer
->Path();
292 SetLabel(timer
->Title());
293 m_dateTime
= timer
->StartAsLocalTime();
296 if (!timer
->ChannelIcon().empty())
297 SetArt("icon", timer
->ChannelIcon());
298 else if (timer
->IsRadio())
299 SetArt("icon", "DefaultMusicSongs.png");
301 SetArt("icon", "DefaultTVShows.png");
303 // Speedup FillInDefaultIcon()
304 SetProperty("icon_never_overlay", true);
306 FillInMimeType(false);
309 CFileItem::CFileItem(const CArtist
& artist
)
312 SetLabel(artist
.strArtist
);
313 m_strPath
= artist
.strArtist
;
315 URIUtils::AddSlashAtEnd(m_strPath
);
316 GetMusicInfoTag()->SetArtist(artist
);
317 FillInMimeType(false);
320 CFileItem::CFileItem(const CGenre
& genre
)
323 SetLabel(genre
.strGenre
);
324 m_strPath
= genre
.strGenre
;
326 URIUtils::AddSlashAtEnd(m_strPath
);
327 GetMusicInfoTag()->SetGenre(genre
.strGenre
);
328 FillInMimeType(false);
331 CFileItem::CFileItem(const CFileItem
& item
)
332 : CGUIListItem(item
),
333 m_musicInfoTag(NULL
),
334 m_videoInfoTag(NULL
),
335 m_pictureInfoTag(NULL
),
341 CFileItem::CFileItem(const CGUIListItem
& item
)
344 // not particularly pretty, but it gets around the issue of Initialize() defaulting
345 // parameters in the CGUIListItem base class.
346 *static_cast<CGUIListItem
*>(this) = item
;
348 FillInMimeType(false);
351 CFileItem::CFileItem(void)
356 CFileItem::CFileItem(const std::string
& strLabel
)
362 CFileItem::CFileItem(const char* strLabel
)
365 SetLabel(std::string(strLabel
));
368 CFileItem::CFileItem(const CURL
& path
, bool bIsFolder
)
371 m_strPath
= path
.Get();
372 m_bIsFolder
= bIsFolder
;
373 if (m_bIsFolder
&& !m_strPath
.empty() && !IsFileFolder())
374 URIUtils::AddSlashAtEnd(m_strPath
);
375 FillInMimeType(false);
378 CFileItem::CFileItem(const std::string
& strPath
, bool bIsFolder
)
382 m_bIsFolder
= bIsFolder
;
383 if (m_bIsFolder
&& !m_strPath
.empty() && !IsFileFolder())
384 URIUtils::AddSlashAtEnd(m_strPath
);
385 FillInMimeType(false);
388 CFileItem::CFileItem(const CMediaSource
& share
)
392 m_bIsShareOrDrive
= true;
393 m_strPath
= share
.strPath
;
394 if (!IsRSS()) // no slash at end for rss feeds
395 URIUtils::AddSlashAtEnd(m_strPath
);
396 std::string label
= share
.strName
;
397 if (!share
.strStatus
.empty())
398 label
= StringUtils::Format("{} ({})", share
.strName
, share
.strStatus
);
400 m_iLockMode
= share
.m_iLockMode
;
401 m_strLockCode
= share
.m_strLockCode
;
402 m_iHasLock
= share
.m_iHasLock
;
403 m_iBadPwdCount
= share
.m_iBadPwdCount
;
404 m_iDriveType
= share
.m_iDriveType
;
405 SetArt("thumb", share
.m_strThumbnailImage
);
406 SetLabelPreformatted(true);
408 GetVideoInfoTag()->m_strFileNameAndPath
= share
.strDiskUniqueId
; // share.strDiskUniqueId contains disc unique id
409 FillInMimeType(false);
412 CFileItem::CFileItem(std::shared_ptr
<const ADDON::IAddon
> addonInfo
) : m_addonInfo(std::move(addonInfo
))
417 CFileItem::CFileItem(const EventPtr
& eventLogEntry
)
421 m_eventLogEntry
= eventLogEntry
;
422 SetLabel(eventLogEntry
->GetLabel());
423 m_dateTime
= eventLogEntry
->GetDateTime();
424 if (!eventLogEntry
->GetIcon().empty())
425 SetArt("icon", eventLogEntry
->GetIcon());
428 CFileItem::~CFileItem(void)
430 delete m_musicInfoTag
;
431 delete m_videoInfoTag
;
432 delete m_pictureInfoTag
;
433 delete m_gameInfoTag
;
435 m_musicInfoTag
= NULL
;
436 m_videoInfoTag
= NULL
;
437 m_pictureInfoTag
= NULL
;
438 m_gameInfoTag
= NULL
;
441 CFileItem
& CFileItem::operator=(const CFileItem
& item
)
446 CGUIListItem::operator=(item
);
447 m_bLabelPreformatted
=item
.m_bLabelPreformatted
;
449 m_strPath
= item
.m_strPath
;
450 m_strDynPath
= item
.m_strDynPath
;
451 m_bIsParentFolder
= item
.m_bIsParentFolder
;
452 m_iDriveType
= item
.m_iDriveType
;
453 m_bIsShareOrDrive
= item
.m_bIsShareOrDrive
;
454 m_dateTime
= item
.m_dateTime
;
455 m_dwSize
= item
.m_dwSize
;
457 if (item
.m_musicInfoTag
)
460 *m_musicInfoTag
= *item
.m_musicInfoTag
;
462 m_musicInfoTag
= new MUSIC_INFO::CMusicInfoTag(*item
.m_musicInfoTag
);
466 delete m_musicInfoTag
;
467 m_musicInfoTag
= NULL
;
470 if (item
.m_videoInfoTag
)
473 *m_videoInfoTag
= *item
.m_videoInfoTag
;
475 m_videoInfoTag
= new CVideoInfoTag(*item
.m_videoInfoTag
);
479 delete m_videoInfoTag
;
480 m_videoInfoTag
= NULL
;
483 if (item
.m_pictureInfoTag
)
485 if (m_pictureInfoTag
)
486 *m_pictureInfoTag
= *item
.m_pictureInfoTag
;
488 m_pictureInfoTag
= new CPictureInfoTag(*item
.m_pictureInfoTag
);
492 delete m_pictureInfoTag
;
493 m_pictureInfoTag
= NULL
;
496 if (item
.m_gameInfoTag
)
499 *m_gameInfoTag
= *item
.m_gameInfoTag
;
501 m_gameInfoTag
= new CGameInfoTag(*item
.m_gameInfoTag
);
505 delete m_gameInfoTag
;
506 m_gameInfoTag
= NULL
;
509 m_epgInfoTag
= item
.m_epgInfoTag
;
510 m_epgSearchFilter
= item
.m_epgSearchFilter
;
511 m_pvrChannelGroupMemberInfoTag
= item
.m_pvrChannelGroupMemberInfoTag
;
512 m_pvrRecordingInfoTag
= item
.m_pvrRecordingInfoTag
;
513 m_pvrTimerInfoTag
= item
.m_pvrTimerInfoTag
;
514 m_addonInfo
= item
.m_addonInfo
;
515 m_eventLogEntry
= item
.m_eventLogEntry
;
517 m_lStartOffset
= item
.m_lStartOffset
;
518 m_lStartPartNumber
= item
.m_lStartPartNumber
;
519 m_lEndOffset
= item
.m_lEndOffset
;
520 m_strDVDLabel
= item
.m_strDVDLabel
;
521 m_strTitle
= item
.m_strTitle
;
522 m_iprogramCount
= item
.m_iprogramCount
;
523 m_idepth
= item
.m_idepth
;
524 m_iLockMode
= item
.m_iLockMode
;
525 m_strLockCode
= item
.m_strLockCode
;
526 m_iHasLock
= item
.m_iHasLock
;
527 m_iBadPwdCount
= item
.m_iBadPwdCount
;
528 m_bCanQueue
=item
.m_bCanQueue
;
529 m_mimetype
= item
.m_mimetype
;
530 m_extrainfo
= item
.m_extrainfo
;
531 m_specialSort
= item
.m_specialSort
;
532 m_bIsAlbum
= item
.m_bIsAlbum
;
533 m_doContentLookup
= item
.m_doContentLookup
;
537 void CFileItem::Initialize()
539 m_musicInfoTag
= NULL
;
540 m_videoInfoTag
= NULL
;
541 m_pictureInfoTag
= NULL
;
542 m_gameInfoTag
= NULL
;
543 m_bLabelPreformatted
= false;
546 m_bIsParentFolder
= false;
547 m_bIsShareOrDrive
= false;
548 m_iDriveType
= CMediaSource::SOURCE_TYPE_UNKNOWN
;
550 m_lStartPartNumber
= 1;
554 m_iLockMode
= LOCK_MODE_EVERYONE
;
556 m_iHasLock
= LOCK_STATE_NO_LOCK
;
558 m_specialSort
= SortSpecialNone
;
559 m_doContentLookup
= true;
562 void CFileItem::Reset()
564 // CGUIListItem members...
568 m_overlayIcon
= ICON_OVERLAY_NONE
;
572 m_strDVDLabel
.clear();
575 m_strDynPath
.clear();
577 m_strLockCode
.clear();
579 delete m_musicInfoTag
;
581 delete m_videoInfoTag
;
583 m_epgInfoTag
.reset();
584 m_epgSearchFilter
.reset();
585 m_pvrChannelGroupMemberInfoTag
.reset();
586 m_pvrRecordingInfoTag
.reset();
587 m_pvrTimerInfoTag
.reset();
588 delete m_pictureInfoTag
;
589 m_pictureInfoTag
=NULL
;
590 delete m_gameInfoTag
;
591 m_gameInfoTag
= NULL
;
594 m_eventLogEntry
.reset();
600 // do not archive dynamic path
601 void CFileItem::Archive(CArchive
& ar
)
603 CGUIListItem::Archive(ar
);
607 ar
<< m_bIsParentFolder
;
608 ar
<< m_bLabelPreformatted
;
610 ar
<< m_bIsShareOrDrive
;
616 ar
<< m_iprogramCount
;
618 ar
<< m_lStartOffset
;
619 ar
<< m_lStartPartNumber
;
623 ar
<< m_iBadPwdCount
;
629 ar
<< m_doContentLookup
;
634 ar
<< *m_musicInfoTag
;
641 ar
<< *m_videoInfoTag
;
645 if (m_pictureInfoTag
)
648 ar
<< *m_pictureInfoTag
;
655 ar
<< *m_gameInfoTag
;
662 ar
>> m_bIsParentFolder
;
663 ar
>> m_bLabelPreformatted
;
665 ar
>> m_bIsShareOrDrive
;
671 ar
>> m_iprogramCount
;
673 ar
>> m_lStartOffset
;
674 ar
>> m_lStartPartNumber
;
678 m_iLockMode
= (LockType
)temp
;
680 ar
>> m_iBadPwdCount
;
686 m_specialSort
= (SortSpecial
)temp
;
687 ar
>> m_doContentLookup
;
692 ar
>> *GetMusicInfoTag();
695 ar
>> *GetVideoInfoTag();
698 ar
>> *GetPictureInfoTag();
701 ar
>> *GetGameInfoTag();
707 void CFileItem::Serialize(CVariant
& value
) const
709 //CGUIListItem::Serialize(value["CGUIListItem"]);
711 value
["strPath"] = m_strPath
;
712 value
["dateTime"] = (m_dateTime
.IsValid()) ? m_dateTime
.GetAsRFC1123DateTime() : "";
713 value
["lastmodified"] = m_dateTime
.IsValid() ? m_dateTime
.GetAsDBDateTime() : "";
714 value
["size"] = m_dwSize
;
715 value
["DVDLabel"] = m_strDVDLabel
;
716 value
["title"] = m_strTitle
;
717 value
["mimetype"] = m_mimetype
;
718 value
["extrainfo"] = m_extrainfo
;
721 (*m_musicInfoTag
).Serialize(value
["musicInfoTag"]);
724 (*m_videoInfoTag
).Serialize(value
["videoInfoTag"]);
726 if (m_pictureInfoTag
)
727 (*m_pictureInfoTag
).Serialize(value
["pictureInfoTag"]);
730 (*m_gameInfoTag
).Serialize(value
["gameInfoTag"]);
732 if (!m_mapProperties
.empty())
734 auto& customProperties
= value
["customproperties"];
735 for (const auto& prop
: m_mapProperties
)
736 customProperties
[prop
.first
] = prop
.second
;
740 void CFileItem::ToSortable(SortItem
&sortable
, Field field
) const
745 sortable
[FieldPath
] = m_strPath
;
748 sortable
[FieldDate
] = (m_dateTime
.IsValid()) ? m_dateTime
.GetAsDBDateTime() : "";
751 sortable
[FieldSize
] = m_dwSize
;
754 sortable
[FieldDriveType
] = m_iDriveType
;
756 case FieldStartOffset
:
757 sortable
[FieldStartOffset
] = m_lStartOffset
;
760 sortable
[FieldEndOffset
] = m_lEndOffset
;
762 case FieldProgramCount
:
763 sortable
[FieldProgramCount
] = m_iprogramCount
;
766 sortable
[FieldBitrate
] = m_dwSize
;
769 sortable
[FieldTitle
] = m_strTitle
;
772 // If there's ever a need to convert more properties from CGUIListItem it might be
773 // worth to make CGUIListItem implement ISortable as well and call it from here
779 if (HasMusicInfoTag())
780 GetMusicInfoTag()->ToSortable(sortable
, field
);
782 if (HasVideoInfoTag())
783 GetVideoInfoTag()->ToSortable(sortable
, field
);
785 if (HasPictureInfoTag())
786 GetPictureInfoTag()->ToSortable(sortable
, field
);
788 if (HasPVRChannelInfoTag())
789 GetPVRChannelInfoTag()->ToSortable(sortable
, field
);
791 if (HasPVRChannelGroupMemberInfoTag())
792 GetPVRChannelGroupMemberInfoTag()->ToSortable(sortable
, field
);
798 case FieldInstallDate
:
799 sortable
[FieldInstallDate
] = GetAddonInfo()->InstallDate().GetAsDBDateTime();
801 case FieldLastUpdated
:
802 sortable
[FieldLastUpdated
] = GetAddonInfo()->LastUpdated().GetAsDBDateTime();
805 sortable
[FieldLastUsed
] = GetAddonInfo()->LastUsed().GetAsDBDateTime();
812 if (HasGameInfoTag())
813 GetGameInfoTag()->ToSortable(sortable
, field
);
816 m_eventLogEntry
->ToSortable(sortable
, field
);
820 if (field
== FieldUserPreference
)
821 sortable
[FieldUserPreference
] = GetProperty("favourite.index").asString();
825 void CFileItem::ToSortable(SortItem
&sortable
, const Fields
&fields
) const
827 Fields::const_iterator it
;
828 for (it
= fields
.begin(); it
!= fields
.end(); ++it
)
829 ToSortable(sortable
, *it
);
831 /* FieldLabel is used as a fallback by all sorters and therefore has to be present as well */
832 sortable
[FieldLabel
] = GetLabel();
833 /* FieldSortSpecial and FieldFolder are required in conjunction with all other sorters as well */
834 sortable
[FieldSortSpecial
] = m_specialSort
;
835 sortable
[FieldFolder
] = m_bIsFolder
;
838 bool CFileItem::Exists(bool bUseCache
/* = true */) const
840 if (m_strPath
.empty()
842 || IsInternetStream()
844 || IsVirtualDirectoryRoot()
849 if (IsVideoDb() && HasVideoInfoTag())
851 CFileItem
dbItem(m_bIsFolder
? GetVideoInfoTag()->m_strPath
: GetVideoInfoTag()->m_strFileNameAndPath
, m_bIsFolder
);
852 return dbItem
.Exists();
855 std::string strPath
= m_strPath
;
857 if (URIUtils::IsMultiPath(strPath
))
858 strPath
= CMultiPathDirectory::GetFirstPath(strPath
);
860 if (URIUtils::IsStack(strPath
))
861 strPath
= CStackDirectory::GetFirstStackedFile(strPath
);
864 return CDirectory::Exists(strPath
, bUseCache
);
866 return CFile::Exists(strPath
, bUseCache
);
871 bool CFileItem::IsVideo() const
873 /* check preset mime type */
874 if(StringUtils::StartsWithNoCase(m_mimetype
, "video/"))
877 if (HasVideoInfoTag())
880 if (HasGameInfoTag())
883 if (HasMusicInfoTag())
886 if (HasPictureInfoTag())
889 // only tv recordings are videos...
890 if (IsPVRRecording())
891 return !GetPVRRecordingInfoTag()->IsRadio();
893 // ... all other PVR items are not.
897 if (URIUtils::IsDVD(m_strPath
))
900 std::string extension
;
901 if(StringUtils::StartsWithNoCase(m_mimetype
, "application/"))
902 { /* check for some standard types */
903 extension
= m_mimetype
.substr(12);
904 if( StringUtils::EqualsNoCase(extension
, "ogg")
905 || StringUtils::EqualsNoCase(extension
, "mp4")
906 || StringUtils::EqualsNoCase(extension
, "mxf") )
910 //! @todo If the file is a zip file, ask the game clients if any support this
911 // file before assuming it is video.
913 return URIUtils::HasExtension(m_strPath
, CServiceBroker::GetFileExtensionProvider().GetVideoExtensions());
916 bool CFileItem::IsEPG() const
918 return HasEPGInfoTag();
921 bool CFileItem::IsPVRChannel() const
923 return HasPVRChannelInfoTag();
926 bool CFileItem::IsPVRChannelGroup() const
928 return URIUtils::IsPVRChannelGroup(m_strPath
);
931 bool CFileItem::IsPVRRecording() const
933 return HasPVRRecordingInfoTag();
936 bool CFileItem::IsUsablePVRRecording() const
938 return (m_pvrRecordingInfoTag
&& !m_pvrRecordingInfoTag
->IsDeleted());
941 bool CFileItem::IsDeletedPVRRecording() const
943 return (m_pvrRecordingInfoTag
&& m_pvrRecordingInfoTag
->IsDeleted());
946 bool CFileItem::IsInProgressPVRRecording() const
948 return (m_pvrRecordingInfoTag
&& m_pvrRecordingInfoTag
->IsInProgress());
951 bool CFileItem::IsPVRTimer() const
953 return HasPVRTimerInfoTag();
956 bool CFileItem::IsDiscStub() const
958 if (IsVideoDb() && HasVideoInfoTag())
960 CFileItem
dbItem(m_bIsFolder
? GetVideoInfoTag()->m_strPath
: GetVideoInfoTag()->m_strFileNameAndPath
, m_bIsFolder
);
961 return dbItem
.IsDiscStub();
964 return URIUtils::HasExtension(m_strPath
, CServiceBroker::GetFileExtensionProvider().GetDiscStubExtensions());
967 bool CFileItem::IsAudio() const
969 /* check preset mime type */
970 if(StringUtils::StartsWithNoCase(m_mimetype
, "audio/"))
973 if (HasMusicInfoTag())
976 if (HasVideoInfoTag())
979 if (HasPictureInfoTag())
982 if (HasGameInfoTag())
988 if(StringUtils::StartsWithNoCase(m_mimetype
, "application/"))
989 { /* check for some standard types */
990 std::string extension
= m_mimetype
.substr(12);
991 if( StringUtils::EqualsNoCase(extension
, "ogg")
992 || StringUtils::EqualsNoCase(extension
, "mp4")
993 || StringUtils::EqualsNoCase(extension
, "mxf") )
997 //! @todo If the file is a zip file, ask the game clients if any support this
998 // file before assuming it is audio
1000 return URIUtils::HasExtension(m_strPath
, CServiceBroker::GetFileExtensionProvider().GetMusicExtensions());
1003 bool CFileItem::IsDeleted() const
1005 if (HasPVRRecordingInfoTag())
1006 return GetPVRRecordingInfoTag()->IsDeleted();
1011 bool CFileItem::IsAudioBook() const
1013 return IsType(".m4b") || IsType(".mka");
1016 bool CFileItem::IsGame() const
1018 if (HasGameInfoTag())
1021 if (HasVideoInfoTag())
1024 if (HasMusicInfoTag())
1027 if (HasPictureInfoTag())
1034 return CGameUtils::IsStandaloneGame(std::const_pointer_cast
<ADDON::IAddon
>(GetAddonInfo()));
1036 return CGameUtils::HasGameExtension(m_strPath
);
1039 bool CFileItem::IsPicture() const
1041 if (StringUtils::StartsWithNoCase(m_mimetype
, "image/"))
1044 if (HasPictureInfoTag())
1047 if (HasGameInfoTag())
1050 if (HasMusicInfoTag())
1053 if (HasVideoInfoTag())
1056 if (HasPVRTimerInfoTag() || HasPVRChannelInfoTag() || HasPVRChannelGroupMemberInfoTag() ||
1057 HasPVRRecordingInfoTag() || HasEPGInfoTag() || HasEPGSearchFilter())
1060 if (!m_strPath
.empty())
1061 return CUtil::IsPicture(m_strPath
);
1066 bool CFileItem::IsLyrics() const
1068 return URIUtils::HasExtension(m_strPath
, ".cdg|.lrc");
1071 bool CFileItem::IsSubtitle() const
1073 return URIUtils::HasExtension(m_strPath
, CServiceBroker::GetFileExtensionProvider().GetSubtitleExtensions());
1076 bool CFileItem::IsCUESheet() const
1078 return URIUtils::HasExtension(m_strPath
, ".cue");
1081 bool CFileItem::IsInternetStream(const bool bStrictCheck
/* = false */) const
1083 if (HasProperty("IsHTTPDirectory"))
1084 return bStrictCheck
;
1086 if (!m_strDynPath
.empty())
1087 return URIUtils::IsInternetStream(m_strDynPath
, bStrictCheck
);
1089 return URIUtils::IsInternetStream(m_strPath
, bStrictCheck
);
1092 bool CFileItem::IsStreamedFilesystem() const
1094 if (!m_strDynPath
.empty())
1095 return URIUtils::IsStreamedFilesystem(m_strDynPath
);
1097 return URIUtils::IsStreamedFilesystem(m_strPath
);
1100 bool CFileItem::IsFileFolder(EFileFolderType types
) const
1102 EFileFolderType always_type
= EFILEFOLDER_TYPE_ALWAYS
;
1104 /* internet streams are not directly expanded */
1105 if(IsInternetStream())
1106 always_type
= EFILEFOLDER_TYPE_ONCLICK
;
1108 if(types
& always_type
)
1110 if(IsSmartPlayList()
1111 || (IsPlayList() && CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_playlistAsFolders
)
1117 || IsType(".ogg|.oga|.xbt")
1118 #if defined(TARGET_ANDROID)
1125 if (CServiceBroker::IsAddonInterfaceUp() &&
1126 IsType(CServiceBroker::GetFileExtensionProvider().GetFileFolderExtensions().c_str()) &&
1127 CServiceBroker::GetFileExtensionProvider().CanOperateExtension(m_strPath
))
1130 if(types
& EFILEFOLDER_TYPE_ONBROWSE
)
1132 if((IsPlayList() && !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_playlistAsFolders
)
1140 bool CFileItem::IsSmartPlayList() const
1142 if (HasProperty("library.smartplaylist") && GetProperty("library.smartplaylist").asBoolean())
1145 return URIUtils::HasExtension(m_strPath
, ".xsp");
1148 bool CFileItem::IsLibraryFolder() const
1150 if (HasProperty("library.filter") && GetProperty("library.filter").asBoolean())
1153 return URIUtils::IsLibraryFolder(m_strPath
);
1156 bool CFileItem::IsPlayList() const
1158 return CPlayListFactory::IsPlaylist(*this);
1161 bool CFileItem::IsPythonScript() const
1163 return URIUtils::HasExtension(m_strPath
, ".py");
1166 bool CFileItem::IsType(const char *ext
) const
1168 if (!m_strDynPath
.empty())
1169 return URIUtils::HasExtension(m_strDynPath
, ext
);
1171 return URIUtils::HasExtension(m_strPath
, ext
);
1174 bool CFileItem::IsNFO() const
1176 return URIUtils::HasExtension(m_strPath
, ".nfo");
1179 bool CFileItem::IsDiscImage() const
1181 return URIUtils::HasExtension(GetDynPath(), ".img|.iso|.nrg|.udf");
1184 bool CFileItem::IsOpticalMediaFile() const
1186 if (IsDVDFile(false, true))
1192 bool CFileItem::IsDVDFile(bool bVobs
/*= true*/, bool bIfos
/*= true*/) const
1194 std::string strFileName
= URIUtils::GetFileName(GetDynPath());
1197 if (StringUtils::EqualsNoCase(strFileName
, "video_ts.ifo"))
1199 if (StringUtils::StartsWithNoCase(strFileName
, "vts_") && StringUtils::EndsWithNoCase(strFileName
, "_0.ifo") && strFileName
.length() == 12)
1204 if (StringUtils::EqualsNoCase(strFileName
, "video_ts.vob"))
1206 if (StringUtils::StartsWithNoCase(strFileName
, "vts_") && StringUtils::EndsWithNoCase(strFileName
, ".vob"))
1213 bool CFileItem::IsBDFile() const
1215 std::string strFileName
= URIUtils::GetFileName(GetDynPath());
1216 return (StringUtils::EqualsNoCase(strFileName
, "index.bdmv") || StringUtils::EqualsNoCase(strFileName
, "MovieObject.bdmv")
1217 || StringUtils::EqualsNoCase(strFileName
, "INDEX.BDM") || StringUtils::EqualsNoCase(strFileName
, "MOVIEOBJ.BDM"));
1220 bool CFileItem::IsRAR() const
1222 return URIUtils::IsRAR(m_strPath
);
1225 bool CFileItem::IsAPK() const
1227 return URIUtils::IsAPK(m_strPath
);
1230 bool CFileItem::IsZIP() const
1232 return URIUtils::IsZIP(m_strPath
);
1235 bool CFileItem::IsCBZ() const
1237 return URIUtils::HasExtension(m_strPath
, ".cbz");
1240 bool CFileItem::IsCBR() const
1242 return URIUtils::HasExtension(m_strPath
, ".cbr");
1245 bool CFileItem::IsRSS() const
1247 return StringUtils::StartsWithNoCase(m_strPath
, "rss://") || URIUtils::HasExtension(m_strPath
, ".rss")
1248 || StringUtils::StartsWithNoCase(m_strPath
, "rsss://")
1249 || m_mimetype
== "application/rss+xml";
1252 bool CFileItem::IsAndroidApp() const
1254 return URIUtils::IsAndroidApp(m_strPath
);
1257 bool CFileItem::IsStack() const
1259 return URIUtils::IsStack(m_strPath
);
1262 bool CFileItem::IsFavourite() const
1264 return URIUtils::IsFavourite(m_strPath
);
1267 bool CFileItem::IsPlugin() const
1269 return URIUtils::IsPlugin(m_strPath
);
1272 bool CFileItem::IsScript() const
1274 return URIUtils::IsScript(m_strPath
);
1277 bool CFileItem::IsAddonsPath() const
1279 return URIUtils::IsAddonsPath(m_strPath
);
1282 bool CFileItem::IsSourcesPath() const
1284 return URIUtils::IsSourcesPath(m_strPath
);
1287 bool CFileItem::IsMultiPath() const
1289 return URIUtils::IsMultiPath(m_strPath
);
1292 bool CFileItem::IsBluray() const
1294 if (URIUtils::IsBluray(m_strPath
))
1297 CFileItem item
= CFileItem(GetOpticalMediaPath(), false);
1299 return item
.IsBDFile();
1302 bool CFileItem::IsProtectedBlurayDisc() const
1305 path
= URIUtils::AddFileToFolder(GetPath(), "AACS", "Unit_Key_RO.inf");
1306 if (CFile::Exists(path
))
1312 bool CFileItem::IsCDDA() const
1314 return URIUtils::IsCDDA(m_strPath
);
1317 bool CFileItem::IsDVD() const
1319 return URIUtils::IsDVD(m_strPath
) || m_iDriveType
== CMediaSource::SOURCE_TYPE_DVD
;
1322 bool CFileItem::IsOnDVD() const
1324 return URIUtils::IsOnDVD(m_strPath
) || m_iDriveType
== CMediaSource::SOURCE_TYPE_DVD
;
1327 bool CFileItem::IsNfs() const
1329 return URIUtils::IsNfs(m_strPath
);
1332 bool CFileItem::IsOnLAN() const
1334 return URIUtils::IsOnLAN(m_strPath
);
1337 bool CFileItem::IsISO9660() const
1339 return URIUtils::IsISO9660(m_strPath
);
1342 bool CFileItem::IsRemote() const
1344 return URIUtils::IsRemote(m_strPath
);
1347 bool CFileItem::IsSmb() const
1349 return URIUtils::IsSmb(m_strPath
);
1352 bool CFileItem::IsURL() const
1354 return URIUtils::IsURL(m_strPath
);
1357 bool CFileItem::IsPVR() const
1359 return URIUtils::IsPVR(m_strPath
);
1362 bool CFileItem::IsLiveTV() const
1364 return URIUtils::IsLiveTV(m_strPath
);
1367 bool CFileItem::IsHD() const
1369 return URIUtils::IsHD(m_strPath
);
1372 bool CFileItem::IsMusicDb() const
1374 return URIUtils::IsMusicDb(m_strPath
);
1377 bool CFileItem::IsVideoDb() const
1379 return URIUtils::IsVideoDb(m_strPath
);
1382 bool CFileItem::IsVirtualDirectoryRoot() const
1384 return (m_bIsFolder
&& m_strPath
.empty());
1387 bool CFileItem::IsRemovable() const
1389 return IsOnDVD() || IsCDDA() || m_iDriveType
== CMediaSource::SOURCE_TYPE_REMOVABLE
;
1392 bool CFileItem::IsReadOnly() const
1394 if (IsParentFolder())
1397 if (m_bIsShareOrDrive
)
1400 return !CUtil::SupportsWriteFileOperations(m_strPath
);
1403 void CFileItem::FillInDefaultIcon()
1405 if (URIUtils::IsPVRGuideItem(m_strPath
))
1407 // epg items never have a default icon. no need to execute this expensive method.
1408 // when filling epg grid window, easily tens of thousands of epg items are processed.
1412 //CLog::Log(LOGINFO, "FillInDefaultIcon({})", pItem->GetLabel());
1413 // find the default icon for a file or folder item
1414 // for files this can be the (depending on the file type)
1415 // default picture for photo's
1416 // default picture for songs
1417 // default picture for videos
1418 // default picture for shortcuts
1419 // default picture for playlists
1422 // for .. folders the default picture for parent folder
1423 // for other folders the defaultFolder.png
1425 if (GetArt("icon").empty())
1429 /* To reduce the average runtime of this code, this list should
1430 * be ordered with most frequently seen types first. Also bear
1431 * in mind the complexity of the code behind the check in the
1432 * case of IsWhatever() returns false.
1436 if (GetPVRChannelInfoTag()->IsRadio())
1437 SetArt("icon", "DefaultMusicSongs.png");
1439 SetArt("icon", "DefaultTVShows.png");
1441 else if ( IsLiveTV() )
1444 SetArt("icon", "DefaultTVShows.png");
1446 else if ( URIUtils::IsArchive(m_strPath
) )
1448 SetArt("icon", "DefaultFile.png");
1450 else if ( IsUsablePVRRecording() )
1453 SetArt("icon", "DefaultVideo.png");
1455 else if ( IsDeletedPVRRecording() )
1457 // PVR deleted recording
1458 SetArt("icon", "DefaultVideoDeleted.png");
1460 else if ( IsAudio() )
1463 SetArt("icon", "DefaultAudio.png");
1465 else if ( IsVideo() )
1468 SetArt("icon", "DefaultVideo.png");
1470 else if (IsPVRTimer())
1472 SetArt("icon", "DefaultVideo.png");
1474 else if ( IsPicture() )
1477 SetArt("icon", "DefaultPicture.png");
1479 else if ( IsPlayList() || IsSmartPlayList())
1481 SetArt("icon", "DefaultPlaylist.png");
1483 else if ( IsPythonScript() )
1485 SetArt("icon", "DefaultScript.png");
1487 else if (IsFavourite())
1489 SetArt("icon", "DefaultFavourites.png");
1493 // default icon for unknown file type
1494 SetArt("icon", "DefaultFile.png");
1499 if ( IsPlayList() || IsSmartPlayList())
1501 SetArt("icon", "DefaultPlaylist.png");
1503 else if (IsParentFolder())
1505 SetArt("icon", "DefaultFolderBack.png");
1509 SetArt("icon", "DefaultFolder.png");
1513 // Set the icon overlays (if applicable)
1514 if (!HasOverlay() && !HasProperty("icon_never_overlay"))
1516 if (URIUtils::IsInRAR(m_strPath
))
1517 SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR
);
1518 else if (URIUtils::IsInZIP(m_strPath
))
1519 SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP
);
1523 void CFileItem::RemoveExtension()
1528 std::string strLabel
= GetLabel();
1529 URIUtils::RemoveExtension(strLabel
);
1533 void CFileItem::CleanString()
1538 std::string strLabel
= GetLabel();
1539 std::string strTitle
, strTitleAndYear
, strYear
;
1540 CUtil::CleanString(strLabel
, strTitle
, strTitleAndYear
, strYear
, true);
1541 SetLabel(strTitleAndYear
);
1544 void CFileItem::SetLabel(const std::string
&strLabel
)
1546 if (strLabel
== "..")
1548 m_bIsParentFolder
= true;
1550 m_specialSort
= SortSpecialOnTop
;
1551 SetLabelPreformatted(true);
1553 CGUIListItem::SetLabel(strLabel
);
1556 void CFileItem::SetFileSizeLabel()
1558 if(m_bIsFolder
&& m_dwSize
== 0)
1561 SetLabel2(StringUtils::SizeToString(m_dwSize
));
1564 bool CFileItem::CanQueue() const
1569 void CFileItem::SetCanQueue(bool bYesNo
)
1571 m_bCanQueue
= bYesNo
;
1574 bool CFileItem::IsParentFolder() const
1576 return m_bIsParentFolder
;
1579 void CFileItem::FillInMimeType(bool lookup
/*= true*/)
1581 //! @todo adapt this to use CMime::GetMimeType()
1582 if (m_mimetype
.empty())
1585 m_mimetype
= "x-directory/normal";
1586 else if (HasPVRChannelInfoTag())
1587 m_mimetype
= GetPVRChannelInfoTag()->MimeType();
1588 else if (StringUtils::StartsWithNoCase(GetDynPath(), "shout://") ||
1589 StringUtils::StartsWithNoCase(GetDynPath(), "http://") ||
1590 StringUtils::StartsWithNoCase(GetDynPath(), "https://"))
1592 // If lookup is false, bail out early to leave mime type empty
1596 CCurlFile::GetMimeType(GetDynURL(), m_mimetype
);
1598 // try to get mime-type again but with an NSPlayer User-Agent
1599 // in order for server to provide correct mime-type. Allows us
1600 // to properly detect an MMS stream
1601 if (StringUtils::StartsWithNoCase(m_mimetype
, "video/x-ms-"))
1602 CCurlFile::GetMimeType(GetDynURL(), m_mimetype
, "NSPlayer/11.00.6001.7000");
1604 // make sure there are no options set in mime-type
1605 // mime-type can look like "video/x-ms-asf ; charset=utf8"
1606 size_t i
= m_mimetype
.find(';');
1607 if(i
!= std::string::npos
)
1608 m_mimetype
.erase(i
, m_mimetype
.length() - i
);
1609 StringUtils::Trim(m_mimetype
);
1612 m_mimetype
= CMime::GetMimeType(*this);
1614 // if it's still empty set to an unknown type
1615 if (m_mimetype
.empty())
1616 m_mimetype
= "application/octet-stream";
1619 // change protocol to mms for the following mime-type. Allows us to create proper FileMMS.
1620 if(StringUtils::StartsWithNoCase(m_mimetype
, "application/vnd.ms.wms-hdr.asfv1") ||
1621 StringUtils::StartsWithNoCase(m_mimetype
, "application/x-mms-framed"))
1623 if (m_strDynPath
.empty())
1624 m_strDynPath
= m_strPath
;
1626 StringUtils::Replace(m_strDynPath
, "http:", "mms:");
1630 void CFileItem::SetMimeTypeForInternetFile()
1632 if (m_doContentLookup
&& IsInternetStream())
1635 FillInMimeType(true);
1639 bool CFileItem::IsSamePath(const CFileItem
*item
) const
1644 if (!m_strPath
.empty() && item
->GetPath() == m_strPath
)
1646 if (item
->HasProperty("item_start") || HasProperty("item_start"))
1647 return (item
->GetProperty("item_start") == GetProperty("item_start"));
1650 if (HasMusicInfoTag() && item
->HasMusicInfoTag())
1652 if (GetMusicInfoTag()->GetDatabaseId() != -1 && item
->GetMusicInfoTag()->GetDatabaseId() != -1)
1653 return ((GetMusicInfoTag()->GetDatabaseId() == item
->GetMusicInfoTag()->GetDatabaseId()) &&
1654 (GetMusicInfoTag()->GetType() == item
->GetMusicInfoTag()->GetType()));
1656 if (HasVideoInfoTag() && item
->HasVideoInfoTag())
1658 if (GetVideoInfoTag()->m_iDbId
!= -1 && item
->GetVideoInfoTag()->m_iDbId
!= -1)
1659 return ((GetVideoInfoTag()->m_iDbId
== item
->GetVideoInfoTag()->m_iDbId
) &&
1660 (GetVideoInfoTag()->m_type
== item
->GetVideoInfoTag()->m_type
));
1662 if (IsMusicDb() && HasMusicInfoTag())
1664 CFileItem
dbItem(m_musicInfoTag
->GetURL(), false);
1665 if (HasProperty("item_start"))
1666 dbItem
.SetProperty("item_start", GetProperty("item_start"));
1667 return dbItem
.IsSamePath(item
);
1669 if (IsVideoDb() && HasVideoInfoTag())
1671 CFileItem
dbItem(GetVideoInfoTag()->m_strFileNameAndPath
, false);
1672 if (HasProperty("item_start"))
1673 dbItem
.SetProperty("item_start", GetProperty("item_start"));
1674 return dbItem
.IsSamePath(item
);
1676 if (item
->IsMusicDb() && item
->HasMusicInfoTag())
1678 CFileItem
dbItem(item
->m_musicInfoTag
->GetURL(), false);
1679 if (item
->HasProperty("item_start"))
1680 dbItem
.SetProperty("item_start", item
->GetProperty("item_start"));
1681 return IsSamePath(&dbItem
);
1683 if (item
->IsVideoDb() && item
->HasVideoInfoTag())
1685 CFileItem
dbItem(item
->GetVideoInfoTag()->m_strFileNameAndPath
, false);
1686 if (item
->HasProperty("item_start"))
1687 dbItem
.SetProperty("item_start", item
->GetProperty("item_start"));
1688 return IsSamePath(&dbItem
);
1690 if (HasProperty("original_listitem_url"))
1691 return (GetProperty("original_listitem_url") == item
->GetPath());
1695 bool CFileItem::IsAlbum() const
1700 void CFileItem::UpdateInfo(const CFileItem
&item
, bool replaceLabels
/*=true*/)
1702 if (item
.HasVideoInfoTag())
1703 { // copy info across
1704 //! @todo premiered info is normally stored in m_dateTime by the db
1706 if (item
.m_videoInfoTag
)
1709 *m_videoInfoTag
= *item
.m_videoInfoTag
;
1711 m_videoInfoTag
= new CVideoInfoTag(*item
.m_videoInfoTag
);
1716 delete m_videoInfoTag
;
1718 m_videoInfoTag
= new CVideoInfoTag
;
1721 m_pvrRecordingInfoTag
= item
.m_pvrRecordingInfoTag
;
1723 SetOverlayImage(ICON_OVERLAY_UNWATCHED
, GetVideoInfoTag()->GetPlayCount() > 0);
1726 if (item
.HasMusicInfoTag())
1728 *GetMusicInfoTag() = *item
.GetMusicInfoTag();
1731 if (item
.HasPictureInfoTag())
1733 *GetPictureInfoTag() = *item
.GetPictureInfoTag();
1736 if (item
.HasGameInfoTag())
1738 *GetGameInfoTag() = *item
.GetGameInfoTag();
1741 SetDynPath(item
.GetDynPath());
1742 if (replaceLabels
&& !item
.GetLabel().empty())
1743 SetLabel(item
.GetLabel());
1744 if (replaceLabels
&& !item
.GetLabel2().empty())
1745 SetLabel2(item
.GetLabel2());
1746 if (!item
.GetArt().empty())
1747 SetArt(item
.GetArt());
1748 AppendProperties(item
);
1751 void CFileItem::MergeInfo(const CFileItem
& item
)
1753 // TODO: Currently merge the metadata/art info is implemented for video case only
1754 if (item
.HasVideoInfoTag())
1756 if (item
.m_videoInfoTag
)
1759 m_videoInfoTag
->Merge(*item
.m_videoInfoTag
);
1761 m_videoInfoTag
= new CVideoInfoTag(*item
.m_videoInfoTag
);
1764 m_pvrRecordingInfoTag
= item
.m_pvrRecordingInfoTag
;
1766 SetOverlayImage(ICON_OVERLAY_UNWATCHED
, GetVideoInfoTag()->GetPlayCount() > 0);
1769 if (item
.HasMusicInfoTag())
1771 *GetMusicInfoTag() = *item
.GetMusicInfoTag();
1774 if (item
.HasPictureInfoTag())
1776 *GetPictureInfoTag() = *item
.GetPictureInfoTag();
1779 if (item
.HasGameInfoTag())
1781 *GetGameInfoTag() = *item
.GetGameInfoTag();
1784 SetDynPath(item
.GetDynPath());
1785 if (!item
.GetLabel().empty())
1786 SetLabel(item
.GetLabel());
1787 if (!item
.GetLabel2().empty())
1788 SetLabel2(item
.GetLabel2());
1789 if (!item
.GetArt().empty())
1792 AppendArt(item
.GetArt());
1794 SetArt(item
.GetArt());
1796 AppendProperties(item
);
1799 void CFileItem::SetFromVideoInfoTag(const CVideoInfoTag
&video
)
1801 if (!video
.m_strTitle
.empty())
1802 SetLabel(video
.m_strTitle
);
1803 if (video
.m_strFileNameAndPath
.empty())
1805 m_strPath
= video
.m_strPath
;
1806 URIUtils::AddSlashAtEnd(m_strPath
);
1811 m_strPath
= video
.m_strFileNameAndPath
;
1812 m_bIsFolder
= false;
1816 *m_videoInfoTag
= video
;
1818 m_videoInfoTag
= new CVideoInfoTag(video
);
1820 if (video
.m_iSeason
== 0)
1821 SetProperty("isspecial", "true");
1822 FillInDefaultIcon();
1823 FillInMimeType(false);
1828 class CPropertySaveHelper
1831 CPropertySaveHelper(CFileItem
& item
, const std::string
& property
, const std::string
& value
)
1832 : m_item(item
), m_property(property
), m_value(value
)
1836 bool NeedsSave() const { return !m_value
.empty() || m_item
.HasProperty(m_property
); }
1838 std::string
GetValueToSave(const std::string
& currentValue
) const
1842 if (!m_value
.empty())
1844 // Overwrite whatever we have; remember what we had originally.
1845 if (!m_item
.HasProperty(m_property
))
1846 m_item
.SetProperty(m_property
, currentValue
);
1850 else if (m_item
.HasProperty(m_property
))
1852 // Restore original value
1853 value
= m_item
.GetProperty(m_property
).asString();
1854 m_item
.ClearProperty(m_property
);
1862 const std::string m_property
;
1863 const std::string m_value
;
1865 } // unnamed namespace
1867 void CFileItem::SetFromMusicInfoTag(const MUSIC_INFO::CMusicInfoTag
& music
)
1869 const std::string path
= GetPath();
1872 SetPath(music
.GetURL());
1876 const CPropertySaveHelper
dynpath(*this, "OriginalDynPath", music
.GetURL());
1877 if (dynpath
.NeedsSave())
1878 SetDynPath(dynpath
.GetValueToSave(m_strDynPath
));
1881 const CPropertySaveHelper
label(*this, "OriginalLabel", music
.GetTitle());
1882 if (label
.NeedsSave())
1883 SetLabel(label
.GetValueToSave(GetLabel()));
1885 const CPropertySaveHelper
thumb(*this, "OriginalThumb", music
.GetStationArt());
1886 if (thumb
.NeedsSave())
1887 SetArt("thumb", thumb
.GetValueToSave(GetArt("thumb")));
1889 *GetMusicInfoTag() = music
;
1890 FillInDefaultIcon();
1891 FillInMimeType(false);
1894 void CFileItem::SetFromAlbum(const CAlbum
&album
)
1896 if (!album
.strAlbum
.empty())
1897 SetLabel(album
.strAlbum
);
1899 m_strLabel2
= album
.GetAlbumArtistString();
1900 GetMusicInfoTag()->SetAlbum(album
);
1902 if (album
.art
.empty())
1903 SetArt("icon", "DefaultAlbumCover.png");
1908 CMusicDatabase::SetPropertiesFromAlbum(*this,album
);
1909 FillInMimeType(false);
1912 void CFileItem::SetFromSong(const CSong
&song
)
1914 if (!song
.strTitle
.empty())
1915 SetLabel(song
.strTitle
);
1916 if (song
.idSong
> 0)
1918 std::string strExt
= URIUtils::GetExtension(song
.strFileName
);
1919 m_strPath
= StringUtils::Format("musicdb://songs/{}{}", song
.idSong
, strExt
);
1921 else if (!song
.strFileName
.empty())
1922 m_strPath
= song
.strFileName
;
1923 GetMusicInfoTag()->SetSong(song
);
1924 m_lStartOffset
= song
.iStartOffset
;
1925 m_lStartPartNumber
= 1;
1926 SetProperty("item_start", song
.iStartOffset
);
1927 m_lEndOffset
= song
.iEndOffset
;
1928 if (!song
.strThumb
.empty())
1929 SetArt("thumb", song
.strThumb
);
1930 FillInMimeType(false);
1933 std::string
CFileItem::GetOpticalMediaPath() const
1936 path
= URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS.IFO");
1937 if (CFile::Exists(path
))
1940 path
= URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS", "VIDEO_TS.IFO");
1941 if (CFile::Exists(path
))
1944 #ifdef HAVE_LIBBLURAY
1945 path
= URIUtils::AddFileToFolder(GetPath(), "index.bdmv");
1946 if (CFile::Exists(path
))
1949 path
= URIUtils::AddFileToFolder(GetPath(), "BDMV", "index.bdmv");
1950 if (CFile::Exists(path
))
1953 path
= URIUtils::AddFileToFolder(GetPath(), "INDEX.BDM");
1954 if (CFile::Exists(path
))
1957 path
= URIUtils::AddFileToFolder(GetPath(), "BDMV", "INDEX.BDM");
1958 if (CFile::Exists(path
))
1961 return std::string();
1965 * @todo Ideally this (and SetPath) would not be available outside of construction
1966 * for CFileItem objects, or at least restricted to essentially be equivalent
1967 * to construction. This would require re-formulating a bunch of CFileItem
1968 * construction, and also allowing CFileItemList to have its own (public)
1969 * SetURL() function, so for now we give direct access.
1971 void CFileItem::SetURL(const CURL
& url
)
1973 m_strPath
= url
.Get();
1976 const CURL
CFileItem::GetURL() const
1978 CURL
url(m_strPath
);
1982 bool CFileItem::IsURL(const CURL
& url
) const
1984 return IsPath(url
.Get());
1987 bool CFileItem::IsPath(const std::string
& path
, bool ignoreURLOptions
/* = false */) const
1989 return URIUtils::PathEquals(m_strPath
, path
, false, ignoreURLOptions
);
1992 void CFileItem::SetDynURL(const CURL
& url
)
1994 m_strDynPath
= url
.Get();
1997 const CURL
CFileItem::GetDynURL() const
1999 if (!m_strDynPath
.empty())
2001 CURL
url(m_strDynPath
);
2006 CURL
url(m_strPath
);
2011 const std::string
&CFileItem::GetDynPath() const
2013 if (!m_strDynPath
.empty())
2014 return m_strDynPath
;
2019 void CFileItem::SetDynPath(const std::string
&path
)
2021 m_strDynPath
= path
;
2024 void CFileItem::SetCueDocument(const CCueDocumentPtr
& cuePtr
)
2026 m_cueDocument
= cuePtr
;
2029 void CFileItem::LoadEmbeddedCue()
2031 CMusicInfoTag
& tag
= *GetMusicInfoTag();
2035 const std::string embeddedCue
= tag
.GetCueSheet();
2036 if (!embeddedCue
.empty())
2038 CCueDocumentPtr
cuesheet(new CCueDocument
);
2039 if (cuesheet
->ParseTag(embeddedCue
))
2041 std::vector
<std::string
> MediaFileVec
;
2042 cuesheet
->GetMediaFiles(MediaFileVec
);
2043 for (std::vector
<std::string
>::iterator itMedia
= MediaFileVec
.begin();
2044 itMedia
!= MediaFileVec
.end(); ++itMedia
)
2045 cuesheet
->UpdateMediaFile(*itMedia
, GetPath());
2046 SetCueDocument(cuesheet
);
2048 // Clear cuesheet tag having added it to item
2049 tag
.SetCueSheet("");
2053 bool CFileItem::HasCueDocument() const
2055 return (m_cueDocument
.get() != nullptr);
2058 bool CFileItem::LoadTracksFromCueDocument(CFileItemList
& scannedItems
)
2063 const CMusicInfoTag
& tag
= *GetMusicInfoTag();
2066 m_cueDocument
->GetSongs(tracks
);
2068 bool oneFilePerTrack
= m_cueDocument
->IsOneFilePerTrack();
2069 m_cueDocument
.reset();
2071 int tracksFound
= 0;
2072 for (VECSONGS::iterator it
= tracks
.begin(); it
!= tracks
.end(); ++it
)
2075 if (song
.strFileName
== GetPath())
2079 if (song
.strAlbum
.empty() && !tag
.GetAlbum().empty())
2080 song
.strAlbum
= tag
.GetAlbum();
2081 //Pass album artist to final MusicInfoTag object via setting song album artist vector.
2082 if (song
.GetAlbumArtist().empty() && !tag
.GetAlbumArtist().empty())
2083 song
.SetAlbumArtist(tag
.GetAlbumArtist());
2084 if (song
.genre
.empty() && !tag
.GetGenre().empty())
2085 song
.genre
= tag
.GetGenre();
2086 //Pass artist to final MusicInfoTag object via setting song artist description string only.
2087 //Artist credits not used during loading from cue sheet.
2088 if (song
.strArtistDesc
.empty() && !tag
.GetArtistString().empty())
2089 song
.strArtistDesc
= tag
.GetArtistString();
2090 if (tag
.GetDiscNumber())
2091 song
.iTrack
|= (tag
.GetDiscNumber() << 16); // see CMusicInfoTag::GetDiscNumber()
2092 if (!tag
.GetCueSheet().empty())
2093 song
.strCueSheet
= tag
.GetCueSheet();
2096 song
.strReleaseDate
= tag
.GetReleaseDate();
2097 if (song
.embeddedArt
.Empty() && !tag
.GetCoverArtInfo().Empty())
2098 song
.embeddedArt
= tag
.GetCoverArtInfo();
2101 if (!song
.iDuration
&& tag
.GetDuration() > 0)
2102 { // must be the last song
2103 song
.iDuration
= CUtil::ConvertMilliSecsToSecsIntRounded(CUtil::ConvertSecsToMilliSecs(tag
.GetDuration()) - song
.iStartOffset
);
2105 if ( tag
.Loaded() && oneFilePerTrack
&& ! ( tag
.GetAlbum().empty() || tag
.GetArtist().empty() || tag
.GetTitle().empty() ) )
2107 // If there are multiple files in a cue file, the tags from the files should be preferred if they exist.
2108 scannedItems
.Add(CFileItemPtr(new CFileItem(song
, tag
)));
2112 scannedItems
.Add(CFileItemPtr(new CFileItem(song
)));
2117 return tracksFound
!= 0;
2120 /////////////////////////////////////////////////////////////////////////////////
2124 //////////////////////////////////////////////////////////////////////////////////
2126 CFileItemList::CFileItemList()
2127 : CFileItem("", true)
2131 CFileItemList::CFileItemList(const std::string
& strPath
)
2132 : CFileItem(strPath
, true)
2136 CFileItemList::~CFileItemList()
2141 CFileItemPtr
CFileItemList::operator[] (int iItem
)
2146 const CFileItemPtr
CFileItemList::operator[] (int iItem
) const
2151 CFileItemPtr
CFileItemList::operator[] (const std::string
& strPath
)
2153 return Get(strPath
);
2156 const CFileItemPtr
CFileItemList::operator[] (const std::string
& strPath
) const
2158 return Get(strPath
);
2161 void CFileItemList::SetIgnoreURLOptions(bool ignoreURLOptions
)
2163 m_ignoreURLOptions
= ignoreURLOptions
;
2167 m_fastLookup
= false; // Force SetFastlookup to clear map
2168 SetFastLookup(true); // and regenerate map
2172 void CFileItemList::SetFastLookup(bool fastLookup
)
2174 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2176 if (fastLookup
&& !m_fastLookup
)
2177 { // generate the map
2179 for (unsigned int i
=0; i
< m_items
.size(); i
++)
2181 CFileItemPtr pItem
= m_items
[i
];
2182 m_map
.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions
? CURL(pItem
->GetPath()).GetWithoutOptions() : pItem
->GetPath(), pItem
));
2185 if (!fastLookup
&& m_fastLookup
)
2187 m_fastLookup
= fastLookup
;
2190 bool CFileItemList::Contains(const std::string
& fileName
) const
2192 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2195 return m_map
.find(m_ignoreURLOptions
? CURL(fileName
).GetWithoutOptions() : fileName
) != m_map
.end();
2198 for (unsigned int i
= 0; i
< m_items
.size(); i
++)
2200 const CFileItemPtr pItem
= m_items
[i
];
2201 if (pItem
->IsPath(m_ignoreURLOptions
? CURL(fileName
).GetWithoutOptions() : fileName
))
2207 void CFileItemList::Clear()
2209 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2212 m_sortDescription
.sortBy
= SortByNone
;
2213 m_sortDescription
.sortOrder
= SortOrderNone
;
2214 m_sortDescription
.sortAttributes
= SortAttributeNone
;
2215 m_sortIgnoreFolders
= false;
2216 m_cacheToDisc
= CACHE_IF_SLOW
;
2217 m_sortDetails
.clear();
2218 m_replaceListing
= false;
2222 void CFileItemList::ClearItems()
2224 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2225 // make sure we free the memory of the items (these are GUIControls which may have allocated resources)
2227 for (unsigned int i
= 0; i
< m_items
.size(); i
++)
2229 CFileItemPtr item
= m_items
[i
];
2236 void CFileItemList::Add(CFileItemPtr pItem
)
2238 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2240 m_map
.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions
? CURL(pItem
->GetPath()).GetWithoutOptions() : pItem
->GetPath(), pItem
));
2241 m_items
.emplace_back(std::move(pItem
));
2244 void CFileItemList::Add(CFileItem
&& item
)
2246 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2247 auto ptr
= std::make_shared
<CFileItem
>(std::move(item
));
2249 m_map
.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions
? CURL(ptr
->GetPath()).GetWithoutOptions() : ptr
->GetPath(), ptr
));
2250 m_items
.emplace_back(std::move(ptr
));
2253 void CFileItemList::AddFront(const CFileItemPtr
&pItem
, int itemPosition
)
2255 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2257 if (itemPosition
>= 0)
2259 m_items
.insert(m_items
.begin()+itemPosition
, pItem
);
2263 m_items
.insert(m_items
.begin()+(m_items
.size()+itemPosition
), pItem
);
2267 m_map
.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions
? CURL(pItem
->GetPath()).GetWithoutOptions() : pItem
->GetPath(), pItem
));
2271 void CFileItemList::Remove(CFileItem
* pItem
)
2273 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2275 for (IVECFILEITEMS it
= m_items
.begin(); it
!= m_items
.end(); ++it
)
2277 if (pItem
== it
->get())
2282 m_map
.erase(m_ignoreURLOptions
? CURL(pItem
->GetPath()).GetWithoutOptions() : pItem
->GetPath());
2289 VECFILEITEMS::iterator
CFileItemList::erase(VECFILEITEMS::iterator first
,
2290 VECFILEITEMS::iterator last
)
2292 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2293 return m_items
.erase(first
, last
);
2296 void CFileItemList::Remove(int iItem
)
2298 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2300 if (iItem
>= 0 && iItem
< Size())
2302 CFileItemPtr pItem
= *(m_items
.begin() + iItem
);
2305 m_map
.erase(m_ignoreURLOptions
? CURL(pItem
->GetPath()).GetWithoutOptions() : pItem
->GetPath());
2307 m_items
.erase(m_items
.begin() + iItem
);
2311 void CFileItemList::Append(const CFileItemList
& itemlist
)
2313 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2315 for (int i
= 0; i
< itemlist
.Size(); ++i
)
2319 void CFileItemList::Assign(const CFileItemList
& itemlist
, bool append
)
2321 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2325 SetPath(itemlist
.GetPath());
2326 SetLabel(itemlist
.GetLabel());
2327 m_sortDetails
= itemlist
.m_sortDetails
;
2328 m_sortDescription
= itemlist
.m_sortDescription
;
2329 m_replaceListing
= itemlist
.m_replaceListing
;
2330 m_content
= itemlist
.m_content
;
2331 m_mapProperties
= itemlist
.m_mapProperties
;
2332 m_cacheToDisc
= itemlist
.m_cacheToDisc
;
2335 bool CFileItemList::Copy(const CFileItemList
& items
, bool copyItems
/* = true */)
2337 // assign all CFileItem parts
2338 *static_cast<CFileItem
*>(this) = static_cast<const CFileItem
&>(items
);
2340 // assign the rest of the CFileItemList properties
2341 m_replaceListing
= items
.m_replaceListing
;
2342 m_content
= items
.m_content
;
2343 m_mapProperties
= items
.m_mapProperties
;
2344 m_cacheToDisc
= items
.m_cacheToDisc
;
2345 m_sortDetails
= items
.m_sortDetails
;
2346 m_sortDescription
= items
.m_sortDescription
;
2347 m_sortIgnoreFolders
= items
.m_sortIgnoreFolders
;
2351 // make a copy of each item
2352 for (int i
= 0; i
< items
.Size(); i
++)
2354 CFileItemPtr
newItem(new CFileItem(*items
[i
]));
2362 CFileItemPtr
CFileItemList::Get(int iItem
) const
2364 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2366 if (iItem
> -1 && iItem
< (int)m_items
.size())
2367 return m_items
[iItem
];
2369 return CFileItemPtr();
2372 CFileItemPtr
CFileItemList::Get(const std::string
& strPath
) const
2374 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2378 MAPFILEITEMS::const_iterator it
=
2379 m_map
.find(m_ignoreURLOptions
? CURL(strPath
).GetWithoutOptions() : strPath
);
2380 if (it
!= m_map
.end())
2383 return CFileItemPtr();
2386 for (unsigned int i
= 0; i
< m_items
.size(); i
++)
2388 CFileItemPtr pItem
= m_items
[i
];
2389 if (pItem
->IsPath(m_ignoreURLOptions
? CURL(strPath
).GetWithoutOptions() : strPath
))
2393 return CFileItemPtr();
2396 int CFileItemList::Size() const
2398 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2399 return (int)m_items
.size();
2402 bool CFileItemList::IsEmpty() const
2404 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2405 return m_items
.empty();
2408 void CFileItemList::Reserve(size_t iCount
)
2410 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2411 m_items
.reserve(iCount
);
2414 void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func
)
2416 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2417 std::stable_sort(m_items
.begin(), m_items
.end(), func
);
2420 void CFileItemList::FillSortFields(FILEITEMFILLFUNC func
)
2422 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2423 std::for_each(m_items
.begin(), m_items
.end(), func
);
2426 void CFileItemList::Sort(SortBy sortBy
, SortOrder sortOrder
, SortAttribute sortAttributes
/* = SortAttributeNone */)
2428 if (sortBy
== SortByNone
||
2429 (m_sortDescription
.sortBy
== sortBy
&& m_sortDescription
.sortOrder
== sortOrder
&&
2430 m_sortDescription
.sortAttributes
== sortAttributes
))
2433 SortDescription sorting
;
2434 sorting
.sortBy
= sortBy
;
2435 sorting
.sortOrder
= sortOrder
;
2436 sorting
.sortAttributes
= sortAttributes
;
2439 m_sortDescription
= sorting
;
2442 void CFileItemList::Sort(SortDescription sortDescription
)
2444 if (sortDescription
.sortBy
== SortByFile
|| sortDescription
.sortBy
== SortBySortTitle
||
2445 sortDescription
.sortBy
== SortByOriginalTitle
|| sortDescription
.sortBy
== SortByDateAdded
||
2446 sortDescription
.sortBy
== SortByRating
|| sortDescription
.sortBy
== SortByYear
||
2447 sortDescription
.sortBy
== SortByPlaylistOrder
|| sortDescription
.sortBy
== SortByLastPlayed
||
2448 sortDescription
.sortBy
== SortByPlaycount
)
2449 sortDescription
.sortAttributes
= (SortAttribute
)((int)sortDescription
.sortAttributes
| SortAttributeIgnoreFolders
);
2451 if (sortDescription
.sortBy
== SortByNone
||
2452 (m_sortDescription
.sortBy
== sortDescription
.sortBy
&& m_sortDescription
.sortOrder
== sortDescription
.sortOrder
&&
2453 m_sortDescription
.sortAttributes
== sortDescription
.sortAttributes
))
2456 if (m_sortIgnoreFolders
)
2457 sortDescription
.sortAttributes
= (SortAttribute
)((int)sortDescription
.sortAttributes
| SortAttributeIgnoreFolders
);
2459 const Fields fields
= SortUtils::GetFieldsForSorting(sortDescription
.sortBy
);
2460 SortItems
sortItems((size_t)Size());
2461 for (int index
= 0; index
< Size(); index
++)
2463 sortItems
[index
] = std::shared_ptr
<SortItem
>(new SortItem
);
2464 m_items
[index
]->ToSortable(*sortItems
[index
], fields
);
2465 (*sortItems
[index
])[FieldId
] = index
;
2469 SortUtils::Sort(sortDescription
, sortItems
);
2471 // apply the new order to the existing CFileItems
2472 VECFILEITEMS sortedFileItems
;
2473 sortedFileItems
.reserve(Size());
2474 for (SortItems::const_iterator it
= sortItems
.begin(); it
!= sortItems
.end(); ++it
)
2476 CFileItemPtr item
= m_items
[(int)(*it
)->at(FieldId
).asInteger()];
2477 // Set the sort label in the CFileItem
2478 item
->SetSortLabel((*it
)->at(FieldSort
).asWideString());
2480 sortedFileItems
.push_back(item
);
2483 // replace the current list with the re-ordered one
2484 m_items
= std::move(sortedFileItems
);
2487 void CFileItemList::Randomize()
2489 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2490 KODI::UTILS::RandomShuffle(m_items
.begin(), m_items
.end());
2493 void CFileItemList::Archive(CArchive
& ar
)
2495 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2498 CFileItem::Archive(ar
);
2501 if (!m_items
.empty() && m_items
[0]->IsParentFolder())
2504 ar
<< (int)(m_items
.size() - i
);
2506 ar
<< m_ignoreURLOptions
;
2510 ar
<< (int)m_sortDescription
.sortBy
;
2511 ar
<< (int)m_sortDescription
.sortOrder
;
2512 ar
<< (int)m_sortDescription
.sortAttributes
;
2513 ar
<< m_sortIgnoreFolders
;
2514 ar
<< (int)m_cacheToDisc
;
2516 ar
<< (int)m_sortDetails
.size();
2517 for (unsigned int j
= 0; j
< m_sortDetails
.size(); ++j
)
2519 const GUIViewSortDetails
&details
= m_sortDetails
[j
];
2520 ar
<< (int)details
.m_sortDescription
.sortBy
;
2521 ar
<< (int)details
.m_sortDescription
.sortOrder
;
2522 ar
<< (int)details
.m_sortDescription
.sortAttributes
;
2523 ar
<< details
.m_buttonLabel
;
2524 ar
<< details
.m_labelMasks
.m_strLabelFile
;
2525 ar
<< details
.m_labelMasks
.m_strLabelFolder
;
2526 ar
<< details
.m_labelMasks
.m_strLabel2File
;
2527 ar
<< details
.m_labelMasks
.m_strLabel2Folder
;
2532 for (; i
< (int)m_items
.size(); ++i
)
2534 CFileItemPtr pItem
= m_items
[i
];
2540 CFileItemPtr pParent
;
2543 CFileItemPtr pItem
=m_items
[0];
2544 if (pItem
->IsParentFolder())
2545 pParent
.reset(new CFileItem(*pItem
));
2548 SetIgnoreURLOptions(false);
2549 SetFastLookup(false);
2552 CFileItem::Archive(ar
);
2561 m_items
.reserve(iSize
+ 1);
2562 m_items
.push_back(pParent
);
2565 m_items
.reserve(iSize
);
2567 bool ignoreURLOptions
= false;
2568 ar
>> ignoreURLOptions
;
2570 bool fastLookup
= false;
2575 m_sortDescription
.sortBy
= (SortBy
)tempint
;
2577 m_sortDescription
.sortOrder
= (SortOrder
)tempint
;
2579 m_sortDescription
.sortAttributes
= (SortAttribute
)tempint
;
2580 ar
>> m_sortIgnoreFolders
;
2582 m_cacheToDisc
= CACHE_TYPE(tempint
);
2584 unsigned int detailSize
= 0;
2586 for (unsigned int j
= 0; j
< detailSize
; ++j
)
2588 GUIViewSortDetails details
;
2590 details
.m_sortDescription
.sortBy
= (SortBy
)tempint
;
2592 details
.m_sortDescription
.sortOrder
= (SortOrder
)tempint
;
2594 details
.m_sortDescription
.sortAttributes
= (SortAttribute
)tempint
;
2595 ar
>> details
.m_buttonLabel
;
2596 ar
>> details
.m_labelMasks
.m_strLabelFile
;
2597 ar
>> details
.m_labelMasks
.m_strLabelFolder
;
2598 ar
>> details
.m_labelMasks
.m_strLabel2File
;
2599 ar
>> details
.m_labelMasks
.m_strLabel2Folder
;
2600 m_sortDetails
.push_back(details
);
2605 for (int i
= 0; i
< iSize
; ++i
)
2607 CFileItemPtr
pItem(new CFileItem
);
2612 SetIgnoreURLOptions(ignoreURLOptions
);
2613 SetFastLookup(fastLookup
);
2617 void CFileItemList::FillInDefaultIcons()
2619 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2620 for (int i
= 0; i
< (int)m_items
.size(); ++i
)
2622 CFileItemPtr pItem
= m_items
[i
];
2623 pItem
->FillInDefaultIcon();
2627 int CFileItemList::GetFolderCount() const
2629 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2630 int nFolderCount
= 0;
2631 for (int i
= 0; i
< (int)m_items
.size(); i
++)
2633 CFileItemPtr pItem
= m_items
[i
];
2634 if (pItem
->m_bIsFolder
)
2638 return nFolderCount
;
2641 int CFileItemList::GetObjectCount() const
2643 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2645 int numObjects
= (int)m_items
.size();
2646 if (numObjects
&& m_items
[0]->IsParentFolder())
2652 int CFileItemList::GetFileCount() const
2654 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2656 for (int i
= 0; i
< (int)m_items
.size(); i
++)
2658 CFileItemPtr pItem
= m_items
[i
];
2659 if (!pItem
->m_bIsFolder
)
2666 int CFileItemList::GetSelectedCount() const
2668 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2670 for (int i
= 0; i
< (int)m_items
.size(); i
++)
2672 CFileItemPtr pItem
= m_items
[i
];
2673 if (pItem
->IsSelected())
2680 void CFileItemList::FilterCueItems()
2682 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2683 // Handle .CUE sheet files...
2684 std::vector
<std::string
> itemstodelete
;
2685 for (int i
= 0; i
< (int)m_items
.size(); i
++)
2687 CFileItemPtr pItem
= m_items
[i
];
2688 if (!pItem
->m_bIsFolder
)
2689 { // see if it's a .CUE sheet
2690 if (pItem
->IsCUESheet())
2692 CCueDocumentPtr
cuesheet(new CCueDocument
);
2693 if (cuesheet
->ParseFile(pItem
->GetPath()))
2695 std::vector
<std::string
> MediaFileVec
;
2696 cuesheet
->GetMediaFiles(MediaFileVec
);
2698 // queue the cue sheet and the underlying media file for deletion
2699 for (std::vector
<std::string
>::iterator itMedia
= MediaFileVec
.begin();
2700 itMedia
!= MediaFileVec
.end(); ++itMedia
)
2702 std::string strMediaFile
= *itMedia
;
2703 std::string fileFromCue
= strMediaFile
; // save the file from the cue we're matching against,
2704 // as we're going to search for others here...
2705 bool bFoundMediaFile
= CFile::Exists(strMediaFile
);
2706 if (!bFoundMediaFile
)
2708 // try file in same dir, not matching case...
2709 if (Contains(strMediaFile
))
2711 bFoundMediaFile
= true;
2715 // try removing the .cue extension...
2716 strMediaFile
= pItem
->GetPath();
2717 URIUtils::RemoveExtension(strMediaFile
);
2718 CFileItem
item(strMediaFile
, false);
2719 if (item
.IsAudio() && Contains(strMediaFile
))
2721 bFoundMediaFile
= true;
2724 { // try replacing the extension with one of our allowed ones.
2725 std::vector
<std::string
> extensions
= StringUtils::Split(CServiceBroker::GetFileExtensionProvider().GetMusicExtensions(), "|");
2726 for (std::vector
<std::string
>::const_iterator i
= extensions
.begin(); i
!= extensions
.end(); ++i
)
2728 strMediaFile
= URIUtils::ReplaceExtension(pItem
->GetPath(), *i
);
2729 CFileItem
item(strMediaFile
, false);
2730 if (!item
.IsCUESheet() && !item
.IsPlayList() && Contains(strMediaFile
))
2732 bFoundMediaFile
= true;
2739 if (bFoundMediaFile
)
2741 cuesheet
->UpdateMediaFile(fileFromCue
, strMediaFile
);
2742 // apply CUE for later processing
2743 for (int j
= 0; j
< (int)m_items
.size(); j
++)
2745 CFileItemPtr pItem
= m_items
[j
];
2746 if (StringUtils::CompareNoCase(pItem
->GetPath(), strMediaFile
) == 0)
2747 pItem
->SetCueDocument(cuesheet
);
2752 itemstodelete
.push_back(pItem
->GetPath());
2756 // now delete the .CUE files.
2757 for (int i
= 0; i
< (int)itemstodelete
.size(); i
++)
2759 for (int j
= 0; j
< (int)m_items
.size(); j
++)
2761 CFileItemPtr pItem
= m_items
[j
];
2762 if (StringUtils::CompareNoCase(pItem
->GetPath(), itemstodelete
[i
]) == 0)
2763 { // delete this item
2764 m_items
.erase(m_items
.begin() + j
);
2771 // Remove the extensions from the filenames
2772 void CFileItemList::RemoveExtensions()
2774 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2775 for (int i
= 0; i
< Size(); ++i
)
2776 m_items
[i
]->RemoveExtension();
2779 void CFileItemList::Stack(bool stackFiles
/* = true */)
2781 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2784 if (IsVirtualDirectoryRoot() ||
2790 SetProperty("isstacked", true);
2792 // items needs to be sorted for stuff below to work properly
2793 Sort(SortByLabel
, SortOrderAscending
);
2801 void CFileItemList::StackFolders()
2803 // Precompile our REs
2804 VECCREGEXP folderRegExps
;
2805 CRegExp
folderRegExp(true, CRegExp::autoUtf8
);
2806 const std::vector
<std::string
>& strFolderRegExps
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_folderStackRegExps
;
2808 std::vector
<std::string
>::const_iterator strExpression
= strFolderRegExps
.begin();
2809 while (strExpression
!= strFolderRegExps
.end())
2811 if (!folderRegExp
.RegComp(*strExpression
))
2812 CLog::Log(LOGERROR
, "{}: Invalid folder stack RegExp:'{}'", __FUNCTION__
,
2813 strExpression
->c_str());
2815 folderRegExps
.push_back(folderRegExp
);
2820 if (!folderRegExp
.IsCompiled())
2822 CLog::Log(LOGDEBUG
, "{}: No stack expressions available. Skipping folder stacking",
2828 for (int i
= 0; i
< Size(); i
++)
2830 CFileItemPtr item
= Get(i
);
2831 // combined the folder checks
2832 if (item
->m_bIsFolder
)
2834 // only check known fast sources?
2836 // 1. rars and zips may be on slow sources? is this supposed to be allowed?
2837 if( !item
->IsRemote()
2840 || URIUtils::IsInRAR(item
->GetPath())
2841 || URIUtils::IsInZIP(item
->GetPath())
2842 || URIUtils::IsOnLAN(item
->GetPath())
2845 // stack cd# folders if contains only a single video file
2849 VECCREGEXP::iterator expr
= folderRegExps
.begin();
2850 while (!bMatch
&& expr
!= folderRegExps
.end())
2852 //CLog::Log(LOGDEBUG,"{}: Running expression {} on {}", __FUNCTION__, expr->GetPattern(), item->GetLabel());
2853 bMatch
= (expr
->RegFind(item
->GetLabel().c_str()) != -1);
2856 CFileItemList items
;
2857 CDirectory::GetDirectory(item
->GetPath(), items
,
2858 CServiceBroker::GetFileExtensionProvider().GetVideoExtensions(),
2860 // optimized to only traverse listing once by checking for filecount
2861 // and recording last file item for later use
2864 for (int j
= 0; j
< items
.Size(); j
++)
2866 if (!items
[j
]->m_bIsFolder
)
2877 *item
= *items
[index
];
2882 // check for dvd folders
2885 std::string dvdPath
= item
->GetOpticalMediaPath();
2887 if (!dvdPath
.empty())
2889 // NOTE: should this be done for the CD# folders too?
2890 item
->m_bIsFolder
= false;
2891 item
->SetPath(dvdPath
);
2892 item
->SetLabel2("");
2893 item
->SetLabelPreformatted(true);
2894 m_sortDescription
.sortBy
= SortByNone
; /* sorting is now broken */
2902 void CFileItemList::StackFiles()
2904 // Precompile our REs
2905 VECCREGEXP stackRegExps
;
2906 CRegExp
tmpRegExp(true, CRegExp::autoUtf8
);
2907 const std::vector
<std::string
>& strStackRegExps
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoStackRegExps
;
2908 std::vector
<std::string
>::const_iterator strRegExp
= strStackRegExps
.begin();
2909 while (strRegExp
!= strStackRegExps
.end())
2911 if (tmpRegExp
.RegComp(*strRegExp
))
2913 if (tmpRegExp
.GetCaptureTotal() == 4)
2914 stackRegExps
.push_back(tmpRegExp
);
2916 CLog::Log(LOGERROR
, "Invalid video stack RE ({}). Must have 4 captures.",
2917 strRegExp
->c_str());
2922 // now stack the files, some of which may be from the previous stack iteration
2926 CFileItemPtr item1
= Get(i
);
2928 // skip folders, nfo files, playlists
2929 if (item1
->m_bIsFolder
2930 || item1
->IsParentFolder()
2932 || item1
->IsPlayList()
2942 std::string stackName
;
2944 std::string filePath
;
2945 std::vector
<int> stack
;
2946 VECCREGEXP::iterator expr
= stackRegExps
.begin();
2948 URIUtils::Split(item1
->GetPath(), filePath
, file1
);
2949 if (URIUtils::HasEncodedFilename(CURL(filePath
)))
2950 file1
= CURL::Decode(file1
);
2953 while (expr
!= stackRegExps
.end())
2955 if (expr
->RegFind(file1
, offset
) != -1)
2957 std::string Title1
= expr
->GetMatch(1),
2958 Volume1
= expr
->GetMatch(2),
2959 Ignore1
= expr
->GetMatch(3),
2960 Extension1
= expr
->GetMatch(4);
2962 Title1
= file1
.substr(0, expr
->GetSubStart(2));
2966 CFileItemPtr item2
= Get(j
);
2968 // skip folders, nfo files, playlists
2969 if (item2
->m_bIsFolder
2970 || item2
->IsParentFolder()
2972 || item2
->IsPlayList()
2980 std::string file2
, filePath2
;
2981 URIUtils::Split(item2
->GetPath(), filePath2
, file2
);
2982 if (URIUtils::HasEncodedFilename(CURL(filePath2
)) )
2983 file2
= CURL::Decode(file2
);
2985 if (expr
->RegFind(file2
, offset
) != -1)
2987 std::string Title2
= expr
->GetMatch(1),
2988 Volume2
= expr
->GetMatch(2),
2989 Ignore2
= expr
->GetMatch(3),
2990 Extension2
= expr
->GetMatch(4);
2992 Title2
= file2
.substr(0, expr
->GetSubStart(2));
2993 if (StringUtils::EqualsNoCase(Title1
, Title2
))
2995 if (!StringUtils::EqualsNoCase(Volume1
, Volume2
))
2997 if (StringUtils::EqualsNoCase(Ignore1
, Ignore2
) &&
2998 StringUtils::EqualsNoCase(Extension1
, Extension2
))
3002 stackName
= Title1
+ Ignore1
+ Extension1
;
3004 size
+= item1
->m_dwSize
;
3007 size
+= item2
->m_dwSize
;
3016 else if (!StringUtils::EqualsNoCase(Ignore1
, Ignore2
)) // False positive, try again with offset
3018 offset
= expr
->GetSubStart(3);
3021 else // Extension mismatch
3028 else // Title mismatch
3035 else // No match 2, next expression
3044 expr
= stackRegExps
.end();
3051 if (stack
.size() > 1)
3053 // have a stack, remove the items and add the stacked item
3054 // dont actually stack a multipart rar set, just remove all items but the first
3055 std::string stackPath
;
3056 if (Get(stack
[0])->IsRAR())
3057 stackPath
= Get(stack
[0])->GetPath();
3060 CStackDirectory dir
;
3061 stackPath
= dir
.ConstructStackPath(*this, stack
);
3063 item1
->SetPath(stackPath
);
3065 for (unsigned k
= 1; k
< stack
.size(); k
++)
3067 // item->m_bIsFolder = true; // don't treat stacked files as folders
3068 // the label may be in a different char set from the filename (eg over smb
3069 // the label is converted from utf8, but the filename is not)
3070 if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWEXTENSIONS
))
3071 URIUtils::RemoveExtension(stackName
);
3073 item1
->SetLabel(stackName
);
3074 item1
->m_dwSize
= size
;
3082 bool CFileItemList::Load(int windowID
)
3085 auto path
= GetDiscFileCache(windowID
);
3088 if (file
.Open(path
))
3090 CArchive
ar(&file
, CArchive::load
);
3092 CLog::Log(LOGDEBUG
, "Loading items: {}, directory: {} sort method: {}, ascending: {}", Size(),
3093 CURL::GetRedacted(GetPath()), m_sortDescription
.sortBy
,
3094 m_sortDescription
.sortOrder
== SortOrderAscending
? "true" : "false");
3100 catch(const std::out_of_range
&)
3102 CLog::Log(LOGERROR
, "Corrupt archive: {}", CURL::GetRedacted(path
));
3108 bool CFileItemList::Save(int windowID
)
3114 CLog::Log(LOGDEBUG
, "Saving fileitems [{}]", CURL::GetRedacted(GetPath()));
3117 std::string cachefile
= GetDiscFileCache(windowID
);
3118 if (file
.OpenForWrite(cachefile
, true)) // overwrite always
3120 // Before caching save simplified cache file name in every item so the cache file can be
3121 // identifed and removed if the item is updated. List path and options (used for file
3122 // name when list cached) can not be accurately derived from item path.
3123 StringUtils::Replace(cachefile
, "special://temp/archive_cache/", "");
3124 StringUtils::Replace(cachefile
, ".fi", "");
3125 for (const auto& item
: m_items
)
3126 item
->SetProperty("cachefilename", cachefile
);
3128 CArchive
ar(&file
, CArchive::store
);
3130 CLog::Log(LOGDEBUG
, " -- items: {}, sort method: {}, ascending: {}", iSize
,
3131 m_sortDescription
.sortBy
,
3132 m_sortDescription
.sortOrder
== SortOrderAscending
? "true" : "false");
3141 void CFileItemList::RemoveDiscCache(int windowID
) const
3143 RemoveDiscCache(GetDiscFileCache(windowID
));
3146 void CFileItemList::RemoveDiscCache(const std::string
& cacheFile
) const
3148 if (CFile::Exists(cacheFile
))
3150 CLog::Log(LOGDEBUG
, "Clearing cached fileitems [{}]", CURL::GetRedacted(GetPath()));
3151 CFile::Delete(cacheFile
);
3155 void CFileItemList::RemoveDiscCacheCRC(const std::string
& crc
) const
3157 std::string cachefile
= StringUtils::Format("special://temp/archive_cache/{}.fi", crc
);
3158 RemoveDiscCache(cachefile
);
3161 std::string
CFileItemList::GetDiscFileCache(int windowID
) const
3163 std::string
strPath(GetPath());
3164 URIUtils::RemoveSlashAtEnd(strPath
);
3166 uint32_t crc
= Crc32::ComputeFromLowerCase(strPath
);
3168 if (IsCDDA() || IsOnDVD())
3169 return StringUtils::Format("special://temp/archive_cache/r-{:08x}.fi", crc
);
3172 return StringUtils::Format("special://temp/archive_cache/mdb-{:08x}.fi", crc
);
3175 return StringUtils::Format("special://temp/archive_cache/vdb-{:08x}.fi", crc
);
3177 if (IsSmartPlayList())
3178 return StringUtils::Format("special://temp/archive_cache/sp-{:08x}.fi", crc
);
3181 return StringUtils::Format("special://temp/archive_cache/{}-{:08x}.fi", windowID
, crc
);
3183 return StringUtils::Format("special://temp/archive_cache/{:08x}.fi", crc
);
3186 bool CFileItemList::AlwaysCache() const
3188 // some database folders are always cached
3190 return CMusicDatabaseDirectory::CanCache(GetPath());
3192 return CVideoDatabaseDirectory::CanCache(GetPath());
3194 return true; // always cache
3198 std::string
CFileItem::GetUserMusicThumb(bool alwaysCheckRemote
/* = false */, bool fallbackToFolder
/* = false */) const
3200 if (m_strPath
.empty()
3201 || StringUtils::StartsWithNoCase(m_strPath
, "newsmartplaylist://")
3202 || StringUtils::StartsWithNoCase(m_strPath
, "newplaylist://")
3203 || m_bIsShareOrDrive
3204 || IsInternetStream()
3205 || URIUtils::IsUPnP(m_strPath
)
3206 || (URIUtils::IsFTP(m_strPath
) && !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs
)
3209 || IsLibraryFolder()
3214 // we first check for <filename>.tbn or <foldername>.tbn
3215 std::string
fileThumb(GetTBNFile());
3216 if (CFile::Exists(fileThumb
))
3219 // Fall back to folder thumb, if requested
3220 if (!m_bIsFolder
&& fallbackToFolder
)
3222 CFileItem
item(URIUtils::GetDirectory(m_strPath
), true);
3223 return item
.GetUserMusicThumb(alwaysCheckRemote
);
3226 // if a folder, check for folder.jpg
3227 if (m_bIsFolder
&& !IsFileFolder() && (!IsRemote() || alwaysCheckRemote
|| CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MUSICFILES_FINDREMOTETHUMBS
)))
3229 std::vector
<CVariant
> thumbs
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetList(
3230 CSettings::SETTING_MUSICLIBRARY_MUSICTHUMBS
);
3231 for (const auto& i
: thumbs
)
3233 std::string strFileName
= i
.asString();
3234 std::string
folderThumb(GetFolderThumb(strFileName
));
3235 if (CFile::Exists(folderThumb
)) // folder.jpg
3237 size_t period
= strFileName
.find_last_of('.');
3238 if (period
!= std::string::npos
)
3241 std::string name
= strFileName
;
3242 std::string folderThumb1
= folderThumb
;
3244 ext
= strFileName
.substr(period
);
3245 StringUtils::ToUpper(ext
);
3246 StringUtils::Replace(folderThumb1
, strFileName
, name
+ ext
);
3247 if (CFile::Exists(folderThumb1
)) // folder.JPG
3248 return folderThumb1
;
3250 folderThumb1
= folderThumb
;
3251 std::string firstletter
= name
.substr(0, 1);
3252 StringUtils::ToUpper(firstletter
);
3253 name
.replace(0, 1, firstletter
);
3254 StringUtils::Replace(folderThumb1
, strFileName
, name
+ ext
);
3255 if (CFile::Exists(folderThumb1
)) // Folder.JPG
3256 return folderThumb1
;
3258 folderThumb1
= folderThumb
;
3259 StringUtils::ToLower(ext
);
3260 StringUtils::Replace(folderThumb1
, strFileName
, name
+ ext
);
3261 if (CFile::Exists(folderThumb1
)) // Folder.jpg
3262 return folderThumb1
;
3270 // Gets the .tbn filename from a file or folder name.
3271 // <filename>.ext -> <filename>.tbn
3272 // <foldername>/ -> <foldername>.tbn
3273 std::string
CFileItem::GetTBNFile() const
3275 std::string thumbFile
;
3276 std::string strFile
= m_strPath
;
3280 std::string strPath
, strReturn
;
3281 URIUtils::GetParentPath(m_strPath
,strPath
);
3282 CFileItem
item(CStackDirectory::GetFirstStackedFile(strFile
),false);
3283 std::string strTBNFile
= item
.GetTBNFile();
3284 strReturn
= URIUtils::AddFileToFolder(strPath
, URIUtils::GetFileName(strTBNFile
));
3285 if (CFile::Exists(strReturn
))
3288 strFile
= URIUtils::AddFileToFolder(strPath
,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile
)));
3291 if (URIUtils::IsInRAR(strFile
) || URIUtils::IsInZIP(strFile
))
3293 std::string strPath
= URIUtils::GetDirectory(strFile
);
3294 std::string strParent
;
3295 URIUtils::GetParentPath(strPath
,strParent
);
3296 strFile
= URIUtils::AddFileToFolder(strParent
, URIUtils::GetFileName(m_strPath
));
3300 strFile
= url
.GetFileName();
3302 if (m_bIsFolder
&& !IsFileFolder())
3303 URIUtils::RemoveSlashAtEnd(strFile
);
3305 if (!strFile
.empty())
3307 if (m_bIsFolder
&& !IsFileFolder())
3308 thumbFile
= strFile
+ ".tbn"; // folder, so just add ".tbn"
3310 thumbFile
= URIUtils::ReplaceExtension(strFile
, ".tbn");
3311 url
.SetFileName(thumbFile
);
3312 thumbFile
= url
.Get();
3317 bool CFileItem::SkipLocalArt() const
3319 return (m_strPath
.empty()
3320 || StringUtils::StartsWithNoCase(m_strPath
, "newsmartplaylist://")
3321 || StringUtils::StartsWithNoCase(m_strPath
, "newplaylist://")
3322 || m_bIsShareOrDrive
3323 || IsInternetStream()
3324 || URIUtils::IsUPnP(m_strPath
)
3325 || (URIUtils::IsFTP(m_strPath
) && !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs
)
3328 || IsLibraryFolder()
3335 std::string
CFileItem::GetThumbHideIfUnwatched(const CFileItem
* item
) const
3337 const std::shared_ptr
<CSettingList
> setting(std::dynamic_pointer_cast
<CSettingList
>(
3338 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(
3339 CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS
)));
3340 if (setting
&& item
->HasVideoInfoTag() && item
->GetVideoInfoTag()->m_type
== MediaTypeEpisode
&&
3341 item
->GetVideoInfoTag()->GetPlayCount() == 0 &&
3342 !CSettingUtils::FindIntInList(setting
,
3343 CSettings::VIDEOLIBRARY_THUMB_SHOW_UNWATCHED_EPISODE
) &&
3344 item
->HasArt("thumb"))
3346 std::string fanArt
= item
->GetArt("fanart");
3348 return "OverlaySpoiler.png";
3353 return item
->GetArt("thumb");
3356 std::string
CFileItem::FindLocalArt(const std::string
&artFile
, bool useFolder
) const
3364 thumb
= GetLocalArt(artFile
, false);
3365 if (!thumb
.empty() && CFile::Exists(thumb
))
3368 if ((useFolder
|| (m_bIsFolder
&& !IsFileFolder())) && !artFile
.empty())
3370 std::string thumb2
= GetLocalArt(artFile
, true);
3371 if (!thumb2
.empty() && thumb2
!= thumb
&& CFile::Exists(thumb2
))
3377 std::string
CFileItem::GetLocalArtBaseFilename() const
3379 bool useFolder
= false;
3380 return GetLocalArtBaseFilename(useFolder
);
3383 std::string
CFileItem::GetLocalArtBaseFilename(bool& useFolder
) const
3385 std::string strFile
= m_strPath
;
3388 std::string strPath
;
3389 URIUtils::GetParentPath(m_strPath
,strPath
);
3390 strFile
= URIUtils::AddFileToFolder(strPath
, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile
)));
3393 if (URIUtils::IsInRAR(strFile
) || URIUtils::IsInZIP(strFile
))
3395 std::string strPath
= URIUtils::GetDirectory(strFile
);
3396 std::string strParent
;
3397 URIUtils::GetParentPath(strPath
,strParent
);
3398 strFile
= URIUtils::AddFileToFolder(strParent
, URIUtils::GetFileName(strFile
));
3402 strFile
= CMultiPathDirectory::GetFirstPath(m_strPath
);
3404 if (IsOpticalMediaFile())
3405 { // optical media files should be treated like folders
3407 strFile
= GetLocalMetadataPath();
3409 else if (useFolder
&& !(m_bIsFolder
&& !IsFileFolder()))
3410 strFile
= URIUtils::GetDirectory(strFile
);
3415 std::string
CFileItem::GetLocalArt(const std::string
& artFile
, bool useFolder
) const
3417 // no retrieving of empty art files from folders
3418 if (useFolder
&& artFile
.empty())
3421 std::string strFile
= GetLocalArtBaseFilename(useFolder
);
3422 if (strFile
.empty()) // empty filepath -> nothing to find
3427 if (!artFile
.empty())
3428 return URIUtils::AddFileToFolder(strFile
, artFile
);
3432 if (artFile
.empty()) // old thumbnail matching
3433 return URIUtils::ReplaceExtension(strFile
, ".tbn");
3435 return URIUtils::ReplaceExtension(strFile
, "-" + artFile
);
3440 std::string
CFileItem::GetFolderThumb(const std::string
&folderJPG
/* = "folder.jpg" */) const
3442 std::string strFolder
= m_strPath
;
3445 URIUtils::IsInRAR(strFolder
) ||
3446 URIUtils::IsInZIP(strFolder
))
3448 URIUtils::GetParentPath(m_strPath
,strFolder
);
3452 strFolder
= CMultiPathDirectory::GetFirstPath(m_strPath
);
3457 return URIUtils::AddFileToFolder(strFolder
, folderJPG
);
3460 std::string
CFileItem::GetMovieName(bool bUseFolderNames
/* = false */) const
3462 if (IsPlugin() && HasVideoInfoTag() && !GetVideoInfoTag()->m_strTitle
.empty())
3463 return GetVideoInfoTag()->m_strTitle
;
3465 if (IsLabelPreformatted())
3468 if (m_pvrRecordingInfoTag
)
3469 return m_pvrRecordingInfoTag
->m_strTitle
;
3470 else if (URIUtils::IsPVRRecording(m_strPath
))
3472 std::string title
= CPVRRecording::GetTitleFromURL(m_strPath
);
3477 std::string strMovieName
;
3478 if (URIUtils::IsStack(m_strPath
))
3479 strMovieName
= CStackDirectory::GetStackedTitlePath(m_strPath
);
3481 strMovieName
= GetBaseMoviePath(bUseFolderNames
);
3483 URIUtils::RemoveSlashAtEnd(strMovieName
);
3485 return CURL::Decode(URIUtils::GetFileName(strMovieName
));
3488 std::string
CFileItem::GetBaseMoviePath(bool bUseFolderNames
) const
3490 std::string strMovieName
= m_strPath
;
3493 strMovieName
= CMultiPathDirectory::GetFirstPath(m_strPath
);
3495 if (IsOpticalMediaFile())
3496 return GetLocalMetadataPath();
3498 if (bUseFolderNames
&&
3499 (!m_bIsFolder
|| URIUtils::IsInArchive(m_strPath
) ||
3500 (HasVideoInfoTag() && GetVideoInfoTag()->m_iDbId
> 0 && !CMediaTypes::IsContainer(GetVideoInfoTag()->m_type
))))
3502 std::string
name2(strMovieName
);
3503 URIUtils::GetParentPath(name2
,strMovieName
);
3504 if (URIUtils::IsInArchive(m_strPath
))
3506 // Try to get archive itself, if empty take path before
3507 name2
= CURL(m_strPath
).GetHostName();
3509 name2
= strMovieName
;
3511 URIUtils::GetParentPath(name2
, strMovieName
);
3515 return strMovieName
;
3518 std::string
CFileItem::GetLocalFanart() const
3522 if (!HasVideoInfoTag())
3523 return ""; // nothing can be done
3524 CFileItem
dbItem(m_bIsFolder
? GetVideoInfoTag()->m_strPath
: GetVideoInfoTag()->m_strFileNameAndPath
, m_bIsFolder
);
3525 return dbItem
.GetLocalFanart();
3528 std::string strFile2
;
3529 std::string strFile
= m_strPath
;
3532 std::string strPath
;
3533 URIUtils::GetParentPath(m_strPath
,strPath
);
3534 CStackDirectory dir
;
3535 std::string strPath2
;
3536 strPath2
= dir
.GetStackedTitlePath(strFile
);
3537 strFile
= URIUtils::AddFileToFolder(strPath
, URIUtils::GetFileName(strPath2
));
3538 CFileItem
item(dir
.GetFirstStackedFile(m_strPath
),false);
3539 std::string
strTBNFile(URIUtils::ReplaceExtension(item
.GetTBNFile(), "-fanart"));
3540 strFile2
= URIUtils::AddFileToFolder(strPath
, URIUtils::GetFileName(strTBNFile
));
3542 if (URIUtils::IsInRAR(strFile
) || URIUtils::IsInZIP(strFile
))
3544 std::string strPath
= URIUtils::GetDirectory(strFile
);
3545 std::string strParent
;
3546 URIUtils::GetParentPath(strPath
,strParent
);
3547 strFile
= URIUtils::AddFileToFolder(strParent
, URIUtils::GetFileName(m_strPath
));
3550 // no local fanart available for these
3551 if (IsInternetStream()
3552 || URIUtils::IsUPnP(strFile
)
3553 || URIUtils::IsBluray(strFile
)
3558 || (URIUtils::IsFTP(strFile
) && !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs
)
3559 || m_strPath
.empty())
3562 std::string strDir
= URIUtils::GetDirectory(strFile
);
3567 CFileItemList items
;
3568 CDirectory::GetDirectory(strDir
, items
, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS
| DIR_FLAG_READ_CACHE
| DIR_FLAG_NO_FILE_INFO
);
3569 if (IsOpticalMediaFile())
3570 { // grab from the optical media parent folder as well
3571 CFileItemList moreItems
;
3572 CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems
, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS
| DIR_FLAG_READ_CACHE
| DIR_FLAG_NO_FILE_INFO
);
3573 items
.Append(moreItems
);
3576 std::vector
<std::string
> fanarts
= { "fanart" };
3578 strFile
= URIUtils::ReplaceExtension(strFile
, "-fanart");
3579 fanarts
.insert(m_bIsFolder
? fanarts
.end() : fanarts
.begin(), URIUtils::GetFileName(strFile
));
3581 if (!strFile2
.empty())
3582 fanarts
.insert(m_bIsFolder
? fanarts
.end() : fanarts
.begin(), URIUtils::GetFileName(strFile2
));
3584 for (std::vector
<std::string
>::const_iterator i
= fanarts
.begin(); i
!= fanarts
.end(); ++i
)
3586 for (int j
= 0; j
< items
.Size(); j
++)
3588 std::string strCandidate
= URIUtils::GetFileName(items
[j
]->m_strPath
);
3589 URIUtils::RemoveExtension(strCandidate
);
3590 std::string strFanart
= *i
;
3591 URIUtils::RemoveExtension(strFanart
);
3592 if (StringUtils::EqualsNoCase(strCandidate
, strFanart
))
3593 return items
[j
]->m_strPath
;
3600 std::string
CFileItem::GetLocalMetadataPath() const
3602 if (m_bIsFolder
&& !IsFileFolder())
3605 std::string
parent(URIUtils::GetParentPath(m_strPath
));
3606 std::string
parentFolder(parent
);
3607 URIUtils::RemoveSlashAtEnd(parentFolder
);
3608 parentFolder
= URIUtils::GetFileName(parentFolder
);
3609 if (StringUtils::EqualsNoCase(parentFolder
, "VIDEO_TS") || StringUtils::EqualsNoCase(parentFolder
, "BDMV"))
3610 { // go back up another one
3611 parent
= URIUtils::GetParentPath(parent
);
3616 bool CFileItem::LoadMusicTag()
3622 if (HasMusicInfoTag() && m_musicInfoTag
->Loaded())
3625 CMusicDatabase musicDatabase
;
3626 if (musicDatabase
.Open())
3629 if (musicDatabase
.GetSongByFileName(m_strPath
, song
))
3631 GetMusicInfoTag()->SetSong(song
);
3634 musicDatabase
.Close();
3636 // load tag from file
3637 CLog::Log(LOGDEBUG
, "{}: loading tag information for file: {}", __FUNCTION__
, m_strPath
);
3638 CMusicInfoTagLoaderFactory factory
;
3639 std::unique_ptr
<IMusicInfoTagLoader
> pLoader (factory
.CreateLoader(*this));
3642 if (pLoader
->Load(m_strPath
, *GetMusicInfoTag()))
3645 // no tag - try some other things
3648 // we have the tracknumber...
3649 int iTrack
= GetMusicInfoTag()->GetTrackNumber();
3652 std::string strText
= g_localizeStrings
.Get(554); // "Track"
3653 if (!strText
.empty() && strText
[strText
.size() - 1] != ' ')
3655 std::string strTrack
= StringUtils::Format((strText
+ "{}"), iTrack
);
3656 GetMusicInfoTag()->SetTitle(strTrack
);
3657 GetMusicInfoTag()->SetLoaded(true);
3663 std::string fileName
= URIUtils::GetFileName(m_strPath
);
3664 URIUtils::RemoveExtension(fileName
);
3665 for (const std::string
& fileFilter
: CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicTagsFromFileFilters
)
3667 CLabelFormatter
formatter(fileFilter
, "");
3668 if (formatter
.FillMusicTag(fileName
, GetMusicInfoTag()))
3670 GetMusicInfoTag()->SetLoaded(true);
3678 bool CFileItem::LoadGameTag()
3681 if (HasGameInfoTag() && m_gameInfoTag
->IsLoaded())
3687 m_gameInfoTag
->SetLoaded(true);
3692 bool CFileItem::LoadDetails()
3696 if (HasVideoInfoTag())
3703 VIDEODATABASEDIRECTORY::CQueryParams params
;
3704 VIDEODATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(GetPath(), params
);
3706 if (params
.GetMovieId() >= 0)
3707 db
.GetMovieInfo(GetPath(), *GetVideoInfoTag(), static_cast<int>(params
.GetMovieId()));
3708 else if (params
.GetMVideoId() >= 0)
3709 db
.GetMusicVideoInfo(GetPath(), *GetVideoInfoTag(), static_cast<int>(params
.GetMVideoId()));
3710 else if (params
.GetEpisodeId() >= 0)
3711 db
.GetEpisodeInfo(GetPath(), *GetVideoInfoTag(), static_cast<int>(params
.GetEpisodeId()));
3712 else if (params
.GetSetId() >= 0) // movie set
3713 db
.GetSetInfo(static_cast<int>(params
.GetSetId()), *GetVideoInfoTag(), this);
3714 else if (params
.GetTvShowId() >= 0)
3716 if (params
.GetSeason() >= 0)
3718 const int idSeason
= db
.GetSeasonId(static_cast<int>(params
.GetTvShowId()),
3719 static_cast<int>(params
.GetSeason()));
3721 db
.GetSeasonInfo(idSeason
, *GetVideoInfoTag(), this);
3724 db
.GetTvShowInfo(GetPath(), *GetVideoInfoTag(), static_cast<int>(params
.GetTvShowId()),
3736 if (m_bIsFolder
&& URIUtils::IsPVRRecordingFileOrFolder(GetPath()))
3738 if (HasProperty("watchedepisodes") || HasProperty("watched"))
3741 const std::string parentPath
= URIUtils::GetParentPath(GetPath());
3743 //! @todo optimize, find a way to set the details of the directory without loading its content.
3744 CFileItemList items
;
3745 if (CDirectory::GetDirectory(parentPath
, items
, "", XFILE::DIR_FLAG_DEFAULTS
))
3747 const std::string path
= GetPath();
3748 const auto it
= std::find_if(items
.cbegin(), items
.cend(),
3749 [path
](const auto& entry
) { return entry
->GetPath() == path
; });
3750 if (it
!= items
.cend())
3757 CLog::LogF(LOGERROR
, "Error filling item details (path={})", GetPath());
3761 //! @todo add support for other types on demand.
3762 CLog::LogF(LOGDEBUG
, "Unsupported item type (path={})", GetPath());
3766 void CFileItemList::Swap(unsigned int item1
, unsigned int item2
)
3768 if (item1
!= item2
&& item1
< m_items
.size() && item2
< m_items
.size())
3769 std::swap(m_items
[item1
], m_items
[item2
]);
3772 bool CFileItemList::UpdateItem(const CFileItem
*item
)
3777 std::unique_lock
<CCriticalSection
> lock(m_lock
);
3778 for (unsigned int i
= 0; i
< m_items
.size(); i
++)
3780 CFileItemPtr pItem
= m_items
[i
];
3781 if (pItem
->IsSamePath(item
))
3783 pItem
->UpdateInfo(*item
);
3790 void CFileItemList::AddSortMethod(SortBy sortBy
, int buttonLabel
, const LABEL_MASKS
&labelMasks
, SortAttribute sortAttributes
/* = SortAttributeNone */)
3792 AddSortMethod(sortBy
, sortAttributes
, buttonLabel
, labelMasks
);
3795 void CFileItemList::AddSortMethod(SortBy sortBy
, SortAttribute sortAttributes
, int buttonLabel
, const LABEL_MASKS
&labelMasks
)
3797 SortDescription sorting
;
3798 sorting
.sortBy
= sortBy
;
3799 sorting
.sortAttributes
= sortAttributes
;
3801 AddSortMethod(sorting
, buttonLabel
, labelMasks
);
3804 void CFileItemList::AddSortMethod(SortDescription sortDescription
, int buttonLabel
, const LABEL_MASKS
&labelMasks
)
3806 GUIViewSortDetails sort
;
3807 sort
.m_sortDescription
= sortDescription
;
3808 sort
.m_buttonLabel
= buttonLabel
;
3809 sort
.m_labelMasks
= labelMasks
;
3811 m_sortDetails
.push_back(sort
);
3814 void CFileItemList::SetReplaceListing(bool replace
)
3816 m_replaceListing
= replace
;
3819 void CFileItemList::ClearSortState()
3821 m_sortDescription
.sortBy
= SortByNone
;
3822 m_sortDescription
.sortOrder
= SortOrderNone
;
3823 m_sortDescription
.sortAttributes
= SortAttributeNone
;
3826 bool CFileItem::HasVideoInfoTag() const
3828 // Note: CPVRRecording is derived from CVideoInfoTag
3829 return m_pvrRecordingInfoTag
.get() != nullptr || m_videoInfoTag
!= nullptr;
3832 CVideoInfoTag
* CFileItem::GetVideoInfoTag()
3834 // Note: CPVRRecording is derived from CVideoInfoTag
3835 if (m_pvrRecordingInfoTag
)
3836 return m_pvrRecordingInfoTag
.get();
3837 else if (!m_videoInfoTag
)
3838 m_videoInfoTag
= new CVideoInfoTag
;
3840 return m_videoInfoTag
;
3843 const CVideoInfoTag
* CFileItem::GetVideoInfoTag() const
3845 // Note: CPVRRecording is derived from CVideoInfoTag
3846 return m_pvrRecordingInfoTag
? m_pvrRecordingInfoTag
.get() : m_videoInfoTag
;
3849 CPictureInfoTag
* CFileItem::GetPictureInfoTag()
3851 if (!m_pictureInfoTag
)
3852 m_pictureInfoTag
= new CPictureInfoTag
;
3854 return m_pictureInfoTag
;
3857 MUSIC_INFO::CMusicInfoTag
* CFileItem::GetMusicInfoTag()
3859 if (!m_musicInfoTag
)
3860 m_musicInfoTag
= new MUSIC_INFO::CMusicInfoTag
;
3862 return m_musicInfoTag
;
3865 CGameInfoTag
* CFileItem::GetGameInfoTag()
3868 m_gameInfoTag
= new CGameInfoTag
;
3870 return m_gameInfoTag
;
3873 bool CFileItem::HasPVRChannelInfoTag() const
3875 return m_pvrChannelGroupMemberInfoTag
&& m_pvrChannelGroupMemberInfoTag
->Channel() != nullptr;
3878 const std::shared_ptr
<PVR::CPVRChannel
> CFileItem::GetPVRChannelInfoTag() const
3880 return m_pvrChannelGroupMemberInfoTag
? m_pvrChannelGroupMemberInfoTag
->Channel()
3881 : std::shared_ptr
<CPVRChannel
>();
3884 std::string
CFileItem::FindTrailer() const
3886 std::string strFile2
;
3887 std::string strFile
= m_strPath
;
3890 std::string strPath
;
3891 URIUtils::GetParentPath(m_strPath
,strPath
);
3892 CStackDirectory dir
;
3893 std::string strPath2
;
3894 strPath2
= dir
.GetStackedTitlePath(strFile
);
3895 strFile
= URIUtils::AddFileToFolder(strPath
,URIUtils::GetFileName(strPath2
));
3896 CFileItem
item(dir
.GetFirstStackedFile(m_strPath
),false);
3897 std::string
strTBNFile(URIUtils::ReplaceExtension(item
.GetTBNFile(), "-trailer"));
3898 strFile2
= URIUtils::AddFileToFolder(strPath
,URIUtils::GetFileName(strTBNFile
));
3900 if (URIUtils::IsInRAR(strFile
) || URIUtils::IsInZIP(strFile
))
3902 std::string strPath
= URIUtils::GetDirectory(strFile
);
3903 std::string strParent
;
3904 URIUtils::GetParentPath(strPath
,strParent
);
3905 strFile
= URIUtils::AddFileToFolder(strParent
,URIUtils::GetFileName(m_strPath
));
3908 // no local trailer available for these
3909 if (IsInternetStream()
3910 || URIUtils::IsUPnP(strFile
)
3911 || URIUtils::IsBluray(strFile
)
3917 std::string strDir
= URIUtils::GetDirectory(strFile
);
3918 CFileItemList items
;
3919 CDirectory::GetDirectory(strDir
, items
, CServiceBroker::GetFileExtensionProvider().GetVideoExtensions(), DIR_FLAG_READ_CACHE
| DIR_FLAG_NO_FILE_INFO
| DIR_FLAG_NO_FILE_DIRS
);
3920 URIUtils::RemoveExtension(strFile
);
3921 strFile
+= "-trailer";
3922 std::string strFile3
= URIUtils::AddFileToFolder(strDir
, "movie-trailer");
3924 // Precompile our REs
3925 VECCREGEXP matchRegExps
;
3926 CRegExp
tmpRegExp(true, CRegExp::autoUtf8
);
3927 const std::vector
<std::string
>& strMatchRegExps
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_trailerMatchRegExps
;
3929 std::vector
<std::string
>::const_iterator strRegExp
= strMatchRegExps
.begin();
3930 while (strRegExp
!= strMatchRegExps
.end())
3932 if (tmpRegExp
.RegComp(*strRegExp
))
3934 matchRegExps
.push_back(tmpRegExp
);
3939 std::string strTrailer
;
3940 for (int i
= 0; i
< items
.Size(); i
++)
3942 std::string strCandidate
= items
[i
]->m_strPath
;
3943 URIUtils::RemoveExtension(strCandidate
);
3944 if (StringUtils::EqualsNoCase(strCandidate
, strFile
) ||
3945 StringUtils::EqualsNoCase(strCandidate
, strFile2
) ||
3946 StringUtils::EqualsNoCase(strCandidate
, strFile3
))
3948 strTrailer
= items
[i
]->m_strPath
;
3953 VECCREGEXP::iterator expr
= matchRegExps
.begin();
3955 while (expr
!= matchRegExps
.end())
3957 if (expr
->RegFind(strCandidate
) != -1)
3959 strTrailer
= items
[i
]->m_strPath
;
3971 VideoDbContentType
CFileItem::GetVideoContentType() const
3973 VideoDbContentType type
= VideoDbContentType::MOVIES
;
3974 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type
== MediaTypeTvShow
)
3975 type
= VideoDbContentType::TVSHOWS
;
3976 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type
== MediaTypeEpisode
)
3977 return VideoDbContentType::EPISODES
;
3978 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type
== MediaTypeMusicVideo
)
3979 return VideoDbContentType::MUSICVIDEOS
;
3980 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type
== MediaTypeAlbum
)
3981 return VideoDbContentType::MUSICALBUMS
;
3983 CVideoDatabaseDirectory dir
;
3984 VIDEODATABASEDIRECTORY::CQueryParams params
;
3985 dir
.GetQueryParams(m_strPath
, params
);
3986 if (params
.GetSetId() != -1 && params
.GetMovieId() == -1) // movie set
3987 return VideoDbContentType::MOVIE_SETS
;
3992 CFileItem
CFileItem::GetItemToPlay() const
3994 if (HasEPGInfoTag())
3996 const std::shared_ptr
<CPVRChannelGroupMember
> groupMember
=
3997 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Channels
>().GetChannelGroupMember(*this);
3999 return CFileItem(groupMember
);
4004 CBookmark
CFileItem::GetResumePoint() const
4006 if (HasVideoInfoTag())
4007 return GetVideoInfoTag()->GetResumePoint();
4011 bool CFileItem::IsResumePointSet() const
4013 return GetResumePoint().IsSet();
4016 double CFileItem::GetCurrentResumeTime() const
4018 return lrint(GetResumePoint().timeInSeconds
);
4021 bool CFileItem::GetCurrentResumeTimeAndPartNumber(int64_t& startOffset
, int& partNumber
) const
4023 CBookmark
resumePoint(GetResumePoint());
4024 if (resumePoint
.IsSet())
4026 startOffset
= llrint(resumePoint
.timeInSeconds
);
4027 partNumber
= resumePoint
.partNumber
;
4033 bool CFileItem::IsResumable() const
4035 return (!IsNFO() && !IsPlayList()) || IsType(".strm");