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/PlayList.h"
35 #include "playlists/PlayListFactory.h"
36 #include "pvr/PVRManager.h"
37 #include "pvr/channels/PVRChannel.h"
38 #include "pvr/channels/PVRChannelGroupMember.h"
39 #include "pvr/epg/EpgInfoTag.h"
40 #include "pvr/epg/EpgSearchFilter.h"
41 #include "pvr/guilib/PVRGUIActionsChannels.h"
42 #include "pvr/guilib/PVRGUIActionsUtils.h"
43 #include "pvr/recordings/PVRRecording.h"
44 #include "pvr/timers/PVRTimerInfoTag.h"
45 #include "settings/AdvancedSettings.h"
46 #include "settings/SettingUtils.h"
47 #include "settings/Settings.h"
48 #include "settings/SettingsComponent.h"
49 #include "settings/lib/Setting.h"
50 #include "utils/Archive.h"
51 #include "utils/Crc32.h"
52 #include "utils/FileExtensionProvider.h"
53 #include "utils/Mime.h"
54 #include "utils/Random.h"
55 #include "utils/RegExp.h"
56 #include "utils/StringUtils.h"
57 #include "utils/URIUtils.h"
58 #include "utils/Variant.h"
59 #include "utils/log.h"
60 #include "video/Bookmark.h"
61 #include "video/VideoDatabase.h"
62 #include "video/VideoInfoTag.h"
70 using namespace XFILE
;
71 using namespace PLAYLIST
;
72 using namespace MUSIC_INFO
;
76 CFileItem::CFileItem(const CSong
& song
)
82 CFileItem::CFileItem(const CSong
& song
, const CMusicInfoTag
& music
)
86 *GetMusicInfoTag() = music
;
89 CFileItem::CFileItem(const CURL
&url
, const CAlbum
& album
)
93 m_strPath
= url
.Get();
94 URIUtils::AddSlashAtEnd(m_strPath
);
98 CFileItem::CFileItem(const std::string
&path
, const CAlbum
& album
)
103 URIUtils::AddSlashAtEnd(m_strPath
);
107 CFileItem::CFileItem(const CMusicInfoTag
& music
)
110 SetLabel(music
.GetTitle());
111 m_strPath
= music
.GetURL();
112 m_bIsFolder
= URIUtils::HasSlashAtEnd(m_strPath
);
113 *GetMusicInfoTag() = music
;
115 FillInMimeType(false);
118 CFileItem::CFileItem(const CVideoInfoTag
& movie
)
121 SetFromVideoInfoTag(movie
);
126 std::string
GetEpgTagTitle(const std::shared_ptr
<const CPVREpgInfoTag
>& epgTag
)
128 if (CServiceBroker::GetPVRManager().IsParentalLocked(epgTag
))
129 return g_localizeStrings
.Get(19266); // Parental locked
130 else if (epgTag
->Title().empty() &&
131 !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
132 CSettings::SETTING_EPG_HIDENOINFOAVAILABLE
))
133 return g_localizeStrings
.Get(19055); // no information available
135 return epgTag
->Title();
137 } // unnamed namespace
139 void CFileItem::FillMusicInfoTag(const std::shared_ptr
<const CPVREpgInfoTag
>& tag
)
141 CMusicInfoTag
* musictag
= GetMusicInfoTag(); // create (!) the music tag.
145 musictag
->SetTitle(GetEpgTagTitle(tag
));
146 musictag
->SetGenre(tag
->Genre());
147 musictag
->SetDuration(tag
->GetDuration());
148 musictag
->SetURL(tag
->Path());
150 else if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
151 CSettings::SETTING_EPG_HIDENOINFOAVAILABLE
))
153 musictag
->SetTitle(g_localizeStrings
.Get(19055)); // no information available
156 musictag
->SetLoaded(true);
159 CFileItem::CFileItem(const std::shared_ptr
<CPVREpgInfoTag
>& tag
)
165 m_strPath
= tag
->Path();
167 SetLabel(GetEpgTagTitle(tag
));
168 m_dateTime
= tag
->StartAsLocalTime();
170 if (!tag
->IconPath().empty())
172 SetArt("icon", tag
->IconPath());
176 const std::string iconPath
= tag
->ChannelIconPath();
177 if (!iconPath
.empty())
178 SetArt("icon", iconPath
);
179 else if (tag
->IsRadio())
180 SetArt("icon", "DefaultMusicSongs.png");
182 SetArt("icon", "DefaultTVShows.png");
185 // Speedup FillInDefaultIcon()
186 SetProperty("icon_never_overlay", true);
188 if (tag
->IsRadio() && !HasMusicInfoTag())
189 FillMusicInfoTag(tag
);
191 FillInMimeType(false);
194 CFileItem::CFileItem(const std::shared_ptr
<PVR::CPVREpgSearchFilter
>& filter
)
199 m_epgSearchFilter
= filter
;
200 m_strPath
= filter
->GetPath();
202 SetLabel(filter
->GetTitle());
204 const CDateTime lastExec
= filter
->GetLastExecutedDateTime();
205 if (lastExec
.IsValid())
206 m_dateTime
.SetFromUTCDateTime(lastExec
);
208 SetArt("icon", "DefaultPVRSearch.png");
210 // Speedup FillInDefaultIcon()
211 SetProperty("icon_never_overlay", true);
213 FillInMimeType(false);
216 CFileItem::CFileItem(const std::shared_ptr
<CPVRChannelGroupMember
>& channelGroupMember
)
220 const std::shared_ptr
<const CPVRChannel
> channel
= channelGroupMember
->Channel();
222 m_pvrChannelGroupMemberInfoTag
= channelGroupMember
;
224 m_strPath
= channelGroupMember
->Path();
227 SetLabel(channel
->ChannelName());
229 if (!channel
->IconPath().empty())
230 SetArt("icon", channel
->IconPath());
231 else if (channel
->IsRadio())
232 SetArt("icon", "DefaultMusicSongs.png");
234 SetArt("icon", "DefaultTVShows.png");
236 SetProperty("channelid", channel
->ChannelID());
237 SetProperty("path", channelGroupMember
->Path());
238 SetArt("thumb", channel
->IconPath());
240 // Speedup FillInDefaultIcon()
241 SetProperty("icon_never_overlay", true);
243 if (channel
->IsRadio() && !HasMusicInfoTag())
245 const std::shared_ptr
<const CPVREpgInfoTag
> epgNow
= channel
->GetEPGNow();
246 FillMusicInfoTag(epgNow
);
248 FillInMimeType(false);
251 CFileItem::CFileItem(const std::shared_ptr
<CPVRRecording
>& record
)
256 m_pvrRecordingInfoTag
= record
;
257 m_strPath
= record
->m_strFileNameAndPath
;
258 SetLabel(record
->m_strTitle
);
259 m_dateTime
= record
->RecordingTimeAsLocalTime();
260 m_dwSize
= record
->GetSizeInBytes();
264 if (!record
->IconPath().empty())
265 SetArt("icon", record
->IconPath());
268 const std::shared_ptr
<const CPVRChannel
> channel
= record
->Channel();
269 if (channel
&& !channel
->IconPath().empty())
270 SetArt("icon", channel
->IconPath());
271 else if (record
->IsRadio())
272 SetArt("icon", "DefaultMusicSongs.png");
274 SetArt("icon", "DefaultTVShows.png");
277 if (!record
->ThumbnailPath().empty())
278 SetArt("thumb", record
->ThumbnailPath());
280 if (!record
->FanartPath().empty())
281 SetArt("fanart", record
->FanartPath());
283 // Speedup FillInDefaultIcon()
284 SetProperty("icon_never_overlay", true);
286 FillInMimeType(false);
289 CFileItem::CFileItem(const std::shared_ptr
<CPVRTimerInfoTag
>& timer
)
293 m_bIsFolder
= timer
->IsTimerRule();
294 m_pvrTimerInfoTag
= timer
;
295 m_strPath
= timer
->Path();
296 SetLabel(timer
->Title());
297 m_dateTime
= timer
->StartAsLocalTime();
300 if (!timer
->ChannelIcon().empty())
301 SetArt("icon", timer
->ChannelIcon());
302 else if (timer
->IsRadio())
303 SetArt("icon", "DefaultMusicSongs.png");
305 SetArt("icon", "DefaultTVShows.png");
307 // Speedup FillInDefaultIcon()
308 SetProperty("icon_never_overlay", true);
310 FillInMimeType(false);
313 CFileItem::CFileItem(const CArtist
& artist
)
316 SetLabel(artist
.strArtist
);
317 m_strPath
= artist
.strArtist
;
319 URIUtils::AddSlashAtEnd(m_strPath
);
320 GetMusicInfoTag()->SetArtist(artist
);
321 FillInMimeType(false);
324 CFileItem::CFileItem(const CGenre
& genre
)
327 SetLabel(genre
.strGenre
);
328 m_strPath
= genre
.strGenre
;
330 URIUtils::AddSlashAtEnd(m_strPath
);
331 GetMusicInfoTag()->SetGenre(genre
.strGenre
);
332 FillInMimeType(false);
335 CFileItem::CFileItem(const CFileItem
& item
)
336 : CGUIListItem(item
),
337 m_musicInfoTag(NULL
),
338 m_videoInfoTag(NULL
),
339 m_pictureInfoTag(NULL
),
345 CFileItem::CFileItem(const CGUIListItem
& item
)
348 // not particularly pretty, but it gets around the issue of Initialize() defaulting
349 // parameters in the CGUIListItem base class.
350 *static_cast<CGUIListItem
*>(this) = item
;
352 FillInMimeType(false);
355 CFileItem::CFileItem(void)
360 CFileItem::CFileItem(const std::string
& strLabel
)
366 CFileItem::CFileItem(const char* strLabel
)
369 SetLabel(std::string(strLabel
));
372 CFileItem::CFileItem(const CURL
& path
, bool bIsFolder
)
375 m_strPath
= path
.Get();
376 m_bIsFolder
= bIsFolder
;
377 if (m_bIsFolder
&& !m_strPath
.empty() && !IsFileFolder())
378 URIUtils::AddSlashAtEnd(m_strPath
);
379 FillInMimeType(false);
382 CFileItem::CFileItem(const std::string
& strPath
, bool bIsFolder
)
386 m_bIsFolder
= bIsFolder
;
387 if (m_bIsFolder
&& !m_strPath
.empty() && !IsFileFolder())
388 URIUtils::AddSlashAtEnd(m_strPath
);
389 FillInMimeType(false);
392 CFileItem::CFileItem(const CMediaSource
& share
)
396 m_bIsShareOrDrive
= true;
397 m_strPath
= share
.strPath
;
398 if (!IsRSS()) // no slash at end for rss feeds
399 URIUtils::AddSlashAtEnd(m_strPath
);
400 std::string label
= share
.strName
;
401 if (!share
.strStatus
.empty())
402 label
= StringUtils::Format("{} ({})", share
.strName
, share
.strStatus
);
404 m_iLockMode
= share
.m_iLockMode
;
405 m_strLockCode
= share
.m_strLockCode
;
406 m_iHasLock
= share
.m_iHasLock
;
407 m_iBadPwdCount
= share
.m_iBadPwdCount
;
408 m_iDriveType
= share
.m_iDriveType
;
409 SetArt("thumb", share
.m_strThumbnailImage
);
410 SetLabelPreformatted(true);
412 GetVideoInfoTag()->m_strFileNameAndPath
= share
.strDiskUniqueId
; // share.strDiskUniqueId contains disc unique id
413 FillInMimeType(false);
416 CFileItem::CFileItem(std::shared_ptr
<const ADDON::IAddon
> addonInfo
) : m_addonInfo(std::move(addonInfo
))
421 CFileItem::CFileItem(const EventPtr
& eventLogEntry
)
425 m_eventLogEntry
= eventLogEntry
;
426 SetLabel(eventLogEntry
->GetLabel());
427 m_dateTime
= eventLogEntry
->GetDateTime();
428 if (!eventLogEntry
->GetIcon().empty())
429 SetArt("icon", eventLogEntry
->GetIcon());
432 CFileItem::~CFileItem(void)
434 delete m_musicInfoTag
;
435 delete m_videoInfoTag
;
436 delete m_pictureInfoTag
;
437 delete m_gameInfoTag
;
439 m_musicInfoTag
= NULL
;
440 m_videoInfoTag
= NULL
;
441 m_pictureInfoTag
= NULL
;
442 m_gameInfoTag
= NULL
;
445 CFileItem
& CFileItem::operator=(const CFileItem
& item
)
450 CGUIListItem::operator=(item
);
451 m_bLabelPreformatted
=item
.m_bLabelPreformatted
;
453 m_strPath
= item
.m_strPath
;
454 m_strDynPath
= item
.m_strDynPath
;
455 m_bIsParentFolder
= item
.m_bIsParentFolder
;
456 m_iDriveType
= item
.m_iDriveType
;
457 m_bIsShareOrDrive
= item
.m_bIsShareOrDrive
;
458 m_dateTime
= item
.m_dateTime
;
459 m_dwSize
= item
.m_dwSize
;
461 if (item
.m_musicInfoTag
)
464 *m_musicInfoTag
= *item
.m_musicInfoTag
;
466 m_musicInfoTag
= new MUSIC_INFO::CMusicInfoTag(*item
.m_musicInfoTag
);
470 delete m_musicInfoTag
;
471 m_musicInfoTag
= NULL
;
474 if (item
.m_videoInfoTag
)
477 *m_videoInfoTag
= *item
.m_videoInfoTag
;
479 m_videoInfoTag
= new CVideoInfoTag(*item
.m_videoInfoTag
);
483 delete m_videoInfoTag
;
484 m_videoInfoTag
= NULL
;
487 if (item
.m_pictureInfoTag
)
489 if (m_pictureInfoTag
)
490 *m_pictureInfoTag
= *item
.m_pictureInfoTag
;
492 m_pictureInfoTag
= new CPictureInfoTag(*item
.m_pictureInfoTag
);
496 delete m_pictureInfoTag
;
497 m_pictureInfoTag
= NULL
;
500 if (item
.m_gameInfoTag
)
503 *m_gameInfoTag
= *item
.m_gameInfoTag
;
505 m_gameInfoTag
= new CGameInfoTag(*item
.m_gameInfoTag
);
509 delete m_gameInfoTag
;
510 m_gameInfoTag
= NULL
;
513 m_epgInfoTag
= item
.m_epgInfoTag
;
514 m_epgSearchFilter
= item
.m_epgSearchFilter
;
515 m_pvrChannelGroupMemberInfoTag
= item
.m_pvrChannelGroupMemberInfoTag
;
516 m_pvrRecordingInfoTag
= item
.m_pvrRecordingInfoTag
;
517 m_pvrTimerInfoTag
= item
.m_pvrTimerInfoTag
;
518 m_addonInfo
= item
.m_addonInfo
;
519 m_eventLogEntry
= item
.m_eventLogEntry
;
521 m_lStartOffset
= item
.m_lStartOffset
;
522 m_lStartPartNumber
= item
.m_lStartPartNumber
;
523 m_lEndOffset
= item
.m_lEndOffset
;
524 m_strDVDLabel
= item
.m_strDVDLabel
;
525 m_strTitle
= item
.m_strTitle
;
526 m_iprogramCount
= item
.m_iprogramCount
;
527 m_idepth
= item
.m_idepth
;
528 m_iLockMode
= item
.m_iLockMode
;
529 m_strLockCode
= item
.m_strLockCode
;
530 m_iHasLock
= item
.m_iHasLock
;
531 m_iBadPwdCount
= item
.m_iBadPwdCount
;
532 m_bCanQueue
=item
.m_bCanQueue
;
533 m_mimetype
= item
.m_mimetype
;
534 m_extrainfo
= item
.m_extrainfo
;
535 m_specialSort
= item
.m_specialSort
;
536 m_bIsAlbum
= item
.m_bIsAlbum
;
537 m_doContentLookup
= item
.m_doContentLookup
;
541 void CFileItem::Initialize()
543 m_musicInfoTag
= NULL
;
544 m_videoInfoTag
= NULL
;
545 m_pictureInfoTag
= NULL
;
546 m_gameInfoTag
= NULL
;
547 m_bLabelPreformatted
= false;
550 m_bIsParentFolder
= false;
551 m_bIsShareOrDrive
= false;
552 m_iDriveType
= CMediaSource::SOURCE_TYPE_UNKNOWN
;
554 m_lStartPartNumber
= 1;
558 m_iLockMode
= LOCK_MODE_EVERYONE
;
560 m_iHasLock
= LOCK_STATE_NO_LOCK
;
562 m_specialSort
= SortSpecialNone
;
563 m_doContentLookup
= true;
566 void CFileItem::Reset()
568 // CGUIListItem members...
572 m_overlayIcon
= ICON_OVERLAY_NONE
;
576 m_strDVDLabel
.clear();
579 m_strDynPath
.clear();
581 m_strLockCode
.clear();
583 delete m_musicInfoTag
;
585 delete m_videoInfoTag
;
587 m_epgInfoTag
.reset();
588 m_epgSearchFilter
.reset();
589 m_pvrChannelGroupMemberInfoTag
.reset();
590 m_pvrRecordingInfoTag
.reset();
591 m_pvrTimerInfoTag
.reset();
592 delete m_pictureInfoTag
;
593 m_pictureInfoTag
=NULL
;
594 delete m_gameInfoTag
;
595 m_gameInfoTag
= NULL
;
598 m_eventLogEntry
.reset();
604 // do not archive dynamic path
605 void CFileItem::Archive(CArchive
& ar
)
607 CGUIListItem::Archive(ar
);
611 ar
<< m_bIsParentFolder
;
612 ar
<< m_bLabelPreformatted
;
614 ar
<< m_bIsShareOrDrive
;
620 ar
<< m_iprogramCount
;
622 ar
<< m_lStartOffset
;
623 ar
<< m_lStartPartNumber
;
627 ar
<< m_iBadPwdCount
;
633 ar
<< m_doContentLookup
;
638 ar
<< *m_musicInfoTag
;
645 ar
<< *m_videoInfoTag
;
649 if (m_pictureInfoTag
)
652 ar
<< *m_pictureInfoTag
;
659 ar
<< *m_gameInfoTag
;
666 ar
>> m_bIsParentFolder
;
667 ar
>> m_bLabelPreformatted
;
669 ar
>> m_bIsShareOrDrive
;
675 ar
>> m_iprogramCount
;
677 ar
>> m_lStartOffset
;
678 ar
>> m_lStartPartNumber
;
682 m_iLockMode
= (LockType
)temp
;
684 ar
>> m_iBadPwdCount
;
690 m_specialSort
= (SortSpecial
)temp
;
691 ar
>> m_doContentLookup
;
696 ar
>> *GetMusicInfoTag();
699 ar
>> *GetVideoInfoTag();
702 ar
>> *GetPictureInfoTag();
705 ar
>> *GetGameInfoTag();
711 void CFileItem::Serialize(CVariant
& value
) const
713 //CGUIListItem::Serialize(value["CGUIListItem"]);
715 value
["strPath"] = m_strPath
;
716 value
["dateTime"] = (m_dateTime
.IsValid()) ? m_dateTime
.GetAsRFC1123DateTime() : "";
717 value
["lastmodified"] = m_dateTime
.IsValid() ? m_dateTime
.GetAsDBDateTime() : "";
718 value
["size"] = m_dwSize
;
719 value
["DVDLabel"] = m_strDVDLabel
;
720 value
["title"] = m_strTitle
;
721 value
["mimetype"] = m_mimetype
;
722 value
["extrainfo"] = m_extrainfo
;
725 (*m_musicInfoTag
).Serialize(value
["musicInfoTag"]);
728 (*m_videoInfoTag
).Serialize(value
["videoInfoTag"]);
730 if (m_pictureInfoTag
)
731 (*m_pictureInfoTag
).Serialize(value
["pictureInfoTag"]);
734 (*m_gameInfoTag
).Serialize(value
["gameInfoTag"]);
736 if (!m_mapProperties
.empty())
738 auto& customProperties
= value
["customproperties"];
739 for (const auto& prop
: m_mapProperties
)
740 customProperties
[prop
.first
] = prop
.second
;
744 void CFileItem::ToSortable(SortItem
&sortable
, Field field
) const
749 sortable
[FieldPath
] = m_strPath
;
752 sortable
[FieldDate
] = (m_dateTime
.IsValid()) ? m_dateTime
.GetAsDBDateTime() : "";
755 sortable
[FieldSize
] = m_dwSize
;
758 sortable
[FieldDriveType
] = m_iDriveType
;
760 case FieldStartOffset
:
761 sortable
[FieldStartOffset
] = m_lStartOffset
;
764 sortable
[FieldEndOffset
] = m_lEndOffset
;
766 case FieldProgramCount
:
767 sortable
[FieldProgramCount
] = m_iprogramCount
;
770 sortable
[FieldBitrate
] = m_dwSize
;
773 sortable
[FieldTitle
] = m_strTitle
;
776 // If there's ever a need to convert more properties from CGUIListItem it might be
777 // worth to make CGUIListItem implement ISortable as well and call it from here
783 if (HasMusicInfoTag())
784 GetMusicInfoTag()->ToSortable(sortable
, field
);
786 if (HasVideoInfoTag())
787 GetVideoInfoTag()->ToSortable(sortable
, field
);
789 if (HasPictureInfoTag())
790 GetPictureInfoTag()->ToSortable(sortable
, field
);
792 if (HasPVRChannelInfoTag())
793 GetPVRChannelInfoTag()->ToSortable(sortable
, field
);
795 if (HasPVRChannelGroupMemberInfoTag())
796 GetPVRChannelGroupMemberInfoTag()->ToSortable(sortable
, field
);
802 case FieldInstallDate
:
803 sortable
[FieldInstallDate
] = GetAddonInfo()->InstallDate().GetAsDBDateTime();
805 case FieldLastUpdated
:
806 sortable
[FieldLastUpdated
] = GetAddonInfo()->LastUpdated().GetAsDBDateTime();
809 sortable
[FieldLastUsed
] = GetAddonInfo()->LastUsed().GetAsDBDateTime();
816 if (HasGameInfoTag())
817 GetGameInfoTag()->ToSortable(sortable
, field
);
820 m_eventLogEntry
->ToSortable(sortable
, field
);
824 if (field
== FieldUserPreference
)
825 sortable
[FieldUserPreference
] = GetProperty("favourite.index").asString();
829 void CFileItem::ToSortable(SortItem
&sortable
, const Fields
&fields
) const
831 Fields::const_iterator it
;
832 for (it
= fields
.begin(); it
!= fields
.end(); ++it
)
833 ToSortable(sortable
, *it
);
835 /* FieldLabel is used as a fallback by all sorters and therefore has to be present as well */
836 sortable
[FieldLabel
] = GetLabel();
837 /* FieldSortSpecial and FieldFolder are required in conjunction with all other sorters as well */
838 sortable
[FieldSortSpecial
] = m_specialSort
;
839 sortable
[FieldFolder
] = m_bIsFolder
;
842 bool CFileItem::Exists(bool bUseCache
/* = true */) const
844 if (m_strPath
.empty()
846 || IsInternetStream()
848 || IsVirtualDirectoryRoot()
853 if (IsVideoDb() && HasVideoInfoTag())
855 CFileItem
dbItem(m_bIsFolder
? GetVideoInfoTag()->m_strPath
: GetVideoInfoTag()->m_strFileNameAndPath
, m_bIsFolder
);
856 return dbItem
.Exists();
859 std::string strPath
= m_strPath
;
861 if (URIUtils::IsMultiPath(strPath
))
862 strPath
= CMultiPathDirectory::GetFirstPath(strPath
);
864 if (URIUtils::IsStack(strPath
))
865 strPath
= CStackDirectory::GetFirstStackedFile(strPath
);
868 return CDirectory::Exists(strPath
, bUseCache
);
870 return CFile::Exists(strPath
, bUseCache
);
875 bool CFileItem::IsVideo() const
877 /* check preset mime type */
878 if(StringUtils::StartsWithNoCase(m_mimetype
, "video/"))
881 if (HasVideoInfoTag())
884 if (HasGameInfoTag())
887 if (HasMusicInfoTag())
890 if (HasPictureInfoTag())
893 // TV recordings are videos...
894 if (!m_bIsFolder
&& URIUtils::IsPVRTVRecordingFileOrFolder(GetPath()))
897 // ... all other PVR items are not.
901 if (URIUtils::IsDVD(m_strPath
))
904 std::string extension
;
905 if(StringUtils::StartsWithNoCase(m_mimetype
, "application/"))
906 { /* check for some standard types */
907 extension
= m_mimetype
.substr(12);
908 if( StringUtils::EqualsNoCase(extension
, "ogg")
909 || StringUtils::EqualsNoCase(extension
, "mp4")
910 || StringUtils::EqualsNoCase(extension
, "mxf") )
914 //! @todo If the file is a zip file, ask the game clients if any support this
915 // file before assuming it is video.
917 return URIUtils::HasExtension(m_strPath
, CServiceBroker::GetFileExtensionProvider().GetVideoExtensions());
920 bool CFileItem::IsEPG() const
922 return HasEPGInfoTag();
925 bool CFileItem::IsPVRChannel() const
927 return HasPVRChannelInfoTag();
930 bool CFileItem::IsPVRChannelGroup() const
932 return URIUtils::IsPVRChannelGroup(m_strPath
);
935 bool CFileItem::IsPVRRecording() const
937 return HasPVRRecordingInfoTag();
940 bool CFileItem::IsUsablePVRRecording() const
942 return (m_pvrRecordingInfoTag
&& !m_pvrRecordingInfoTag
->IsDeleted());
945 bool CFileItem::IsDeletedPVRRecording() const
947 return (m_pvrRecordingInfoTag
&& m_pvrRecordingInfoTag
->IsDeleted());
950 bool CFileItem::IsInProgressPVRRecording() const
952 return (m_pvrRecordingInfoTag
&& m_pvrRecordingInfoTag
->IsInProgress());
955 bool CFileItem::IsPVRTimer() const
957 return HasPVRTimerInfoTag();
960 bool CFileItem::IsDiscStub() const
962 if (IsVideoDb() && HasVideoInfoTag())
964 CFileItem
dbItem(m_bIsFolder
? GetVideoInfoTag()->m_strPath
: GetVideoInfoTag()->m_strFileNameAndPath
, m_bIsFolder
);
965 return dbItem
.IsDiscStub();
968 return URIUtils::HasExtension(m_strPath
, CServiceBroker::GetFileExtensionProvider().GetDiscStubExtensions());
971 bool CFileItem::IsAudio() const
973 /* check preset mime type */
974 if(StringUtils::StartsWithNoCase(m_mimetype
, "audio/"))
977 if (HasMusicInfoTag())
980 if (HasVideoInfoTag())
983 if (HasPictureInfoTag())
986 if (HasGameInfoTag())
992 if(StringUtils::StartsWithNoCase(m_mimetype
, "application/"))
993 { /* check for some standard types */
994 std::string extension
= m_mimetype
.substr(12);
995 if( StringUtils::EqualsNoCase(extension
, "ogg")
996 || StringUtils::EqualsNoCase(extension
, "mp4")
997 || StringUtils::EqualsNoCase(extension
, "mxf") )
1001 //! @todo If the file is a zip file, ask the game clients if any support this
1002 // file before assuming it is audio
1004 return URIUtils::HasExtension(m_strPath
, CServiceBroker::GetFileExtensionProvider().GetMusicExtensions());
1007 bool CFileItem::IsDeleted() const
1009 if (HasPVRRecordingInfoTag())
1010 return GetPVRRecordingInfoTag()->IsDeleted();
1015 bool CFileItem::IsAudioBook() const
1017 return IsType(".m4b") || IsType(".mka");
1020 bool CFileItem::IsGame() const
1022 if (HasGameInfoTag())
1025 if (HasVideoInfoTag())
1028 if (HasMusicInfoTag())
1031 if (HasPictureInfoTag())
1038 return CGameUtils::IsStandaloneGame(std::const_pointer_cast
<ADDON::IAddon
>(GetAddonInfo()));
1040 return CGameUtils::HasGameExtension(m_strPath
);
1043 bool CFileItem::IsPicture() const
1045 if (StringUtils::StartsWithNoCase(m_mimetype
, "image/"))
1048 if (HasPictureInfoTag())
1051 if (HasGameInfoTag())
1054 if (HasMusicInfoTag())
1057 if (HasVideoInfoTag())
1060 if (HasPVRTimerInfoTag() || HasPVRChannelInfoTag() || HasPVRChannelGroupMemberInfoTag() ||
1061 HasPVRRecordingInfoTag() || HasEPGInfoTag() || HasEPGSearchFilter())
1064 if (!m_strPath
.empty())
1065 return CUtil::IsPicture(m_strPath
);
1070 bool CFileItem::IsLyrics() const
1072 return URIUtils::HasExtension(m_strPath
, ".cdg|.lrc");
1075 bool CFileItem::IsSubtitle() const
1077 return URIUtils::HasExtension(m_strPath
, CServiceBroker::GetFileExtensionProvider().GetSubtitleExtensions());
1080 bool CFileItem::IsCUESheet() const
1082 return URIUtils::HasExtension(m_strPath
, ".cue");
1085 bool CFileItem::IsInternetStream(const bool bStrictCheck
/* = false */) const
1087 if (HasProperty("IsHTTPDirectory"))
1088 return bStrictCheck
;
1090 if (!m_strDynPath
.empty())
1091 return URIUtils::IsInternetStream(m_strDynPath
, bStrictCheck
);
1093 return URIUtils::IsInternetStream(m_strPath
, bStrictCheck
);
1096 bool CFileItem::IsStreamedFilesystem() const
1098 if (!m_strDynPath
.empty())
1099 return URIUtils::IsStreamedFilesystem(m_strDynPath
);
1101 return URIUtils::IsStreamedFilesystem(m_strPath
);
1104 bool CFileItem::IsFileFolder(EFileFolderType types
) const
1106 EFileFolderType always_type
= EFILEFOLDER_TYPE_ALWAYS
;
1108 /* internet streams are not directly expanded */
1109 if(IsInternetStream())
1110 always_type
= EFILEFOLDER_TYPE_ONCLICK
;
1112 // strm files are not browsable
1113 if (IsType(".strm") && (types
& EFILEFOLDER_TYPE_ONBROWSE
))
1116 if(types
& always_type
)
1118 if(IsSmartPlayList()
1119 || (IsPlayList() && CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_playlistAsFolders
)
1125 || IsType(".ogg|.oga|.xbt")
1126 #if defined(TARGET_ANDROID)
1133 if (CServiceBroker::IsAddonInterfaceUp() &&
1134 IsType(CServiceBroker::GetFileExtensionProvider().GetFileFolderExtensions().c_str()) &&
1135 CServiceBroker::GetFileExtensionProvider().CanOperateExtension(m_strPath
))
1138 if(types
& EFILEFOLDER_TYPE_ONBROWSE
)
1140 if((IsPlayList() && !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_playlistAsFolders
)
1148 bool CFileItem::IsSmartPlayList() const
1150 if (HasProperty("library.smartplaylist") && GetProperty("library.smartplaylist").asBoolean())
1153 return URIUtils::HasExtension(m_strPath
, ".xsp");
1156 bool CFileItem::IsLibraryFolder() const
1158 if (HasProperty("library.filter") && GetProperty("library.filter").asBoolean())
1161 return URIUtils::IsLibraryFolder(m_strPath
);
1164 bool CFileItem::IsPlayList() const
1166 return CPlayListFactory::IsPlaylist(*this);
1169 bool CFileItem::IsPythonScript() const
1171 return URIUtils::HasExtension(m_strPath
, ".py");
1174 bool CFileItem::IsType(const char *ext
) const
1176 if (!m_strDynPath
.empty())
1177 return URIUtils::HasExtension(m_strDynPath
, ext
);
1179 return URIUtils::HasExtension(m_strPath
, ext
);
1182 bool CFileItem::IsNFO() const
1184 return URIUtils::HasExtension(m_strPath
, ".nfo");
1187 bool CFileItem::IsVideoExtras() const
1189 return m_bIsFolder
&&
1190 StringUtils::EqualsNoCase(URIUtils::GetFileOrFolderName(m_strPath
), "extras");
1193 bool CFileItem::IsDiscImage() const
1195 return URIUtils::IsDiscImage(GetDynPath());
1198 bool CFileItem::IsOpticalMediaFile() const
1200 if (IsDVDFile(false, true))
1206 bool CFileItem::IsDVDFile(bool bVobs
/*= true*/, bool bIfos
/*= true*/) const
1208 std::string strFileName
= URIUtils::GetFileName(GetDynPath());
1211 if (StringUtils::EqualsNoCase(strFileName
, "video_ts.ifo"))
1213 if (StringUtils::StartsWithNoCase(strFileName
, "vts_") && StringUtils::EndsWithNoCase(strFileName
, "_0.ifo") && strFileName
.length() == 12)
1218 if (StringUtils::EqualsNoCase(strFileName
, "video_ts.vob"))
1220 if (StringUtils::StartsWithNoCase(strFileName
, "vts_") && StringUtils::EndsWithNoCase(strFileName
, ".vob"))
1227 bool CFileItem::IsBDFile() const
1229 std::string strFileName
= URIUtils::GetFileName(GetDynPath());
1230 return (StringUtils::EqualsNoCase(strFileName
, "index.bdmv") || StringUtils::EqualsNoCase(strFileName
, "MovieObject.bdmv")
1231 || StringUtils::EqualsNoCase(strFileName
, "INDEX.BDM") || StringUtils::EqualsNoCase(strFileName
, "MOVIEOBJ.BDM"));
1234 bool CFileItem::IsRAR() const
1236 return URIUtils::IsRAR(m_strPath
);
1239 bool CFileItem::IsAPK() const
1241 return URIUtils::IsAPK(m_strPath
);
1244 bool CFileItem::IsZIP() const
1246 return URIUtils::IsZIP(m_strPath
);
1249 bool CFileItem::IsCBZ() const
1251 return URIUtils::HasExtension(m_strPath
, ".cbz");
1254 bool CFileItem::IsCBR() const
1256 return URIUtils::HasExtension(m_strPath
, ".cbr");
1259 bool CFileItem::IsRSS() const
1261 return StringUtils::StartsWithNoCase(m_strPath
, "rss://") || URIUtils::HasExtension(m_strPath
, ".rss")
1262 || StringUtils::StartsWithNoCase(m_strPath
, "rsss://")
1263 || m_mimetype
== "application/rss+xml";
1266 bool CFileItem::IsAndroidApp() const
1268 return URIUtils::IsAndroidApp(m_strPath
);
1271 bool CFileItem::IsStack() const
1273 return URIUtils::IsStack(m_strPath
);
1276 bool CFileItem::IsFavourite() const
1278 return URIUtils::IsFavourite(m_strPath
);
1281 bool CFileItem::IsPlugin() const
1283 return URIUtils::IsPlugin(m_strPath
);
1286 bool CFileItem::IsScript() const
1288 return URIUtils::IsScript(m_strPath
);
1291 bool CFileItem::IsAddonsPath() const
1293 return URIUtils::IsAddonsPath(m_strPath
);
1296 bool CFileItem::IsSourcesPath() const
1298 return URIUtils::IsSourcesPath(m_strPath
);
1301 bool CFileItem::IsMultiPath() const
1303 return URIUtils::IsMultiPath(m_strPath
);
1306 bool CFileItem::IsBluray() const
1308 if (URIUtils::IsBluray(m_strPath
))
1311 CFileItem item
= CFileItem(GetOpticalMediaPath(), false);
1313 return item
.IsBDFile();
1316 bool CFileItem::IsProtectedBlurayDisc() const
1319 path
= URIUtils::AddFileToFolder(GetPath(), "AACS", "Unit_Key_RO.inf");
1320 if (CFile::Exists(path
))
1326 bool CFileItem::IsCDDA() const
1328 return URIUtils::IsCDDA(m_strPath
);
1331 bool CFileItem::IsDVD() const
1333 return URIUtils::IsDVD(m_strPath
) || m_iDriveType
== CMediaSource::SOURCE_TYPE_DVD
;
1336 bool CFileItem::IsOnDVD() const
1338 return URIUtils::IsOnDVD(m_strPath
) || m_iDriveType
== CMediaSource::SOURCE_TYPE_DVD
;
1341 bool CFileItem::IsNfs() const
1343 return URIUtils::IsNfs(m_strPath
);
1346 bool CFileItem::IsOnLAN() const
1348 return URIUtils::IsOnLAN(m_strPath
);
1351 bool CFileItem::IsISO9660() const
1353 return URIUtils::IsISO9660(m_strPath
);
1356 bool CFileItem::IsRemote() const
1358 return URIUtils::IsRemote(m_strPath
);
1361 bool CFileItem::IsSmb() const
1363 return URIUtils::IsSmb(m_strPath
);
1366 bool CFileItem::IsURL() const
1368 return URIUtils::IsURL(m_strPath
);
1371 bool CFileItem::IsPVR() const
1373 return URIUtils::IsPVR(m_strPath
);
1376 bool CFileItem::IsLiveTV() const
1378 return URIUtils::IsLiveTV(m_strPath
);
1381 bool CFileItem::IsHD() const
1383 return URIUtils::IsHD(m_strPath
);
1386 bool CFileItem::IsMusicDb() const
1388 return URIUtils::IsMusicDb(m_strPath
);
1391 bool CFileItem::IsVideoDb() const
1393 return URIUtils::IsVideoDb(m_strPath
);
1396 bool CFileItem::IsVirtualDirectoryRoot() const
1398 return (m_bIsFolder
&& m_strPath
.empty());
1401 bool CFileItem::IsRemovable() const
1403 return IsOnDVD() || IsCDDA() || m_iDriveType
== CMediaSource::SOURCE_TYPE_REMOVABLE
;
1406 bool CFileItem::IsReadOnly() const
1408 if (IsParentFolder())
1411 if (m_bIsShareOrDrive
)
1414 return !CUtil::SupportsWriteFileOperations(m_strPath
);
1417 void CFileItem::FillInDefaultIcon()
1419 if (URIUtils::IsPVRGuideItem(m_strPath
))
1421 // epg items never have a default icon. no need to execute this expensive method.
1422 // when filling epg grid window, easily tens of thousands of epg items are processed.
1426 //CLog::Log(LOGINFO, "FillInDefaultIcon({})", pItem->GetLabel());
1427 // find the default icon for a file or folder item
1428 // for files this can be the (depending on the file type)
1429 // default picture for photo's
1430 // default picture for songs
1431 // default picture for videos
1432 // default picture for shortcuts
1433 // default picture for playlists
1436 // for .. folders the default picture for parent folder
1437 // for other folders the defaultFolder.png
1439 if (GetArt("icon").empty())
1443 /* To reduce the average runtime of this code, this list should
1444 * be ordered with most frequently seen types first. Also bear
1445 * in mind the complexity of the code behind the check in the
1446 * case of IsWhatever() returns false.
1450 if (GetPVRChannelInfoTag()->IsRadio())
1451 SetArt("icon", "DefaultMusicSongs.png");
1453 SetArt("icon", "DefaultTVShows.png");
1455 else if ( IsLiveTV() )
1458 SetArt("icon", "DefaultTVShows.png");
1460 else if ( URIUtils::IsArchive(m_strPath
) )
1462 SetArt("icon", "DefaultFile.png");
1464 else if ( IsUsablePVRRecording() )
1467 SetArt("icon", "DefaultVideo.png");
1469 else if ( IsDeletedPVRRecording() )
1471 // PVR deleted recording
1472 SetArt("icon", "DefaultVideoDeleted.png");
1474 else if ( IsAudio() )
1477 SetArt("icon", "DefaultAudio.png");
1479 else if ( IsVideo() )
1482 SetArt("icon", "DefaultVideo.png");
1484 else if (IsPVRTimer())
1486 SetArt("icon", "DefaultVideo.png");
1488 else if ( IsPicture() )
1491 SetArt("icon", "DefaultPicture.png");
1493 else if ( IsPlayList() || IsSmartPlayList())
1495 SetArt("icon", "DefaultPlaylist.png");
1497 else if ( IsPythonScript() )
1499 SetArt("icon", "DefaultScript.png");
1501 else if (IsFavourite())
1503 SetArt("icon", "DefaultFavourites.png");
1507 // default icon for unknown file type
1508 SetArt("icon", "DefaultFile.png");
1513 if ( IsPlayList() || IsSmartPlayList())
1515 SetArt("icon", "DefaultPlaylist.png");
1517 else if (IsParentFolder())
1519 SetArt("icon", "DefaultFolderBack.png");
1523 SetArt("icon", "DefaultFolder.png");
1527 // Set the icon overlays (if applicable)
1528 if (!HasOverlay() && !HasProperty("icon_never_overlay"))
1530 if (URIUtils::IsInRAR(m_strPath
))
1531 SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR
);
1532 else if (URIUtils::IsInZIP(m_strPath
))
1533 SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP
);
1537 void CFileItem::RemoveExtension()
1542 std::string strLabel
= GetLabel();
1543 URIUtils::RemoveExtension(strLabel
);
1547 void CFileItem::CleanString()
1552 std::string strLabel
= GetLabel();
1553 std::string strTitle
, strTitleAndYear
, strYear
;
1554 CUtil::CleanString(strLabel
, strTitle
, strTitleAndYear
, strYear
, true);
1555 SetLabel(strTitleAndYear
);
1558 void CFileItem::SetLabel(const std::string
&strLabel
)
1560 if (strLabel
== "..")
1562 m_bIsParentFolder
= true;
1564 m_specialSort
= SortSpecialOnTop
;
1565 SetLabelPreformatted(true);
1567 CGUIListItem::SetLabel(strLabel
);
1570 void CFileItem::SetFileSizeLabel()
1572 if(m_bIsFolder
&& m_dwSize
== 0)
1575 SetLabel2(StringUtils::SizeToString(m_dwSize
));
1578 bool CFileItem::CanQueue() const
1583 void CFileItem::SetCanQueue(bool bYesNo
)
1585 m_bCanQueue
= bYesNo
;
1588 bool CFileItem::IsParentFolder() const
1590 return m_bIsParentFolder
;
1593 void CFileItem::FillInMimeType(bool lookup
/*= true*/)
1595 //! @todo adapt this to use CMime::GetMimeType()
1596 if (m_mimetype
.empty())
1599 m_mimetype
= "x-directory/normal";
1600 else if (HasPVRChannelInfoTag())
1601 m_mimetype
= GetPVRChannelInfoTag()->MimeType();
1602 else if (StringUtils::StartsWithNoCase(GetDynPath(), "shout://") ||
1603 StringUtils::StartsWithNoCase(GetDynPath(), "http://") ||
1604 StringUtils::StartsWithNoCase(GetDynPath(), "https://"))
1606 // If lookup is false, bail out early to leave mime type empty
1610 CCurlFile::GetMimeType(GetDynURL(), m_mimetype
);
1612 // try to get mime-type again but with an NSPlayer User-Agent
1613 // in order for server to provide correct mime-type. Allows us
1614 // to properly detect an MMS stream
1615 if (StringUtils::StartsWithNoCase(m_mimetype
, "video/x-ms-"))
1616 CCurlFile::GetMimeType(GetDynURL(), m_mimetype
, "NSPlayer/11.00.6001.7000");
1618 // make sure there are no options set in mime-type
1619 // mime-type can look like "video/x-ms-asf ; charset=utf8"
1620 size_t i
= m_mimetype
.find(';');
1621 if(i
!= std::string::npos
)
1622 m_mimetype
.erase(i
, m_mimetype
.length() - i
);
1623 StringUtils::Trim(m_mimetype
);
1626 m_mimetype
= CMime::GetMimeType(*this);
1628 // if it's still empty set to an unknown type
1629 if (m_mimetype
.empty())
1630 m_mimetype
= "application/octet-stream";
1633 // change protocol to mms for the following mime-type. Allows us to create proper FileMMS.
1634 if(StringUtils::StartsWithNoCase(m_mimetype
, "application/vnd.ms.wms-hdr.asfv1") ||
1635 StringUtils::StartsWithNoCase(m_mimetype
, "application/x-mms-framed"))
1637 if (m_strDynPath
.empty())
1638 m_strDynPath
= m_strPath
;
1640 StringUtils::Replace(m_strDynPath
, "http:", "mms:");
1644 void CFileItem::UpdateMimeType(bool lookup
/*= true*/)
1646 //! @todo application/octet-stream might actually have been set by a web lookup. Currently we
1647 //! cannot distinguish between set as fallback only (see FillInMimeType) or as an actual value.
1648 if (m_mimetype
== "application/octet-stream")
1651 FillInMimeType(lookup
);
1654 void CFileItem::SetMimeTypeForInternetFile()
1656 if (m_doContentLookup
&& IsInternetStream())
1659 FillInMimeType(true);
1663 bool CFileItem::IsSamePath(const CFileItem
*item
) const
1668 if (!m_strPath
.empty() && item
->GetPath() == m_strPath
)
1670 if (item
->HasProperty("item_start") || HasProperty("item_start"))
1671 return (item
->GetProperty("item_start") == GetProperty("item_start"));
1674 if (HasMusicInfoTag() && item
->HasMusicInfoTag())
1676 if (GetMusicInfoTag()->GetDatabaseId() != -1 && item
->GetMusicInfoTag()->GetDatabaseId() != -1)
1677 return ((GetMusicInfoTag()->GetDatabaseId() == item
->GetMusicInfoTag()->GetDatabaseId()) &&
1678 (GetMusicInfoTag()->GetType() == item
->GetMusicInfoTag()->GetType()));
1680 if (HasVideoInfoTag() && item
->HasVideoInfoTag())
1682 const CVideoInfoTag
* myTag
{GetVideoInfoTag()};
1683 const CVideoInfoTag
* otherTag
{item
->GetVideoInfoTag()};
1684 if (myTag
->m_iDbId
!= -1 && otherTag
->m_iDbId
!= -1)
1686 if ((myTag
->m_iDbId
== otherTag
->m_iDbId
) && (myTag
->m_type
== otherTag
->m_type
))
1688 // for movies with multiple versions, wie need also to check the file id
1689 if (HasVideoVersions() && item
->HasVideoVersions() && myTag
->m_iFileId
!= -1 &&
1690 otherTag
->m_iFileId
!= -1)
1691 return myTag
->m_iFileId
== otherTag
->m_iFileId
;
1696 if (IsMusicDb() && HasMusicInfoTag())
1698 CFileItem
dbItem(m_musicInfoTag
->GetURL(), false);
1699 if (HasProperty("item_start"))
1700 dbItem
.SetProperty("item_start", GetProperty("item_start"));
1701 return dbItem
.IsSamePath(item
);
1703 if (IsVideoDb() && HasVideoInfoTag())
1705 CFileItem
dbItem(GetVideoInfoTag()->m_strFileNameAndPath
, false);
1706 if (HasProperty("item_start"))
1707 dbItem
.SetProperty("item_start", GetProperty("item_start"));
1708 return dbItem
.IsSamePath(item
);
1710 if (item
->IsMusicDb() && item
->HasMusicInfoTag())
1712 CFileItem
dbItem(item
->m_musicInfoTag
->GetURL(), false);
1713 if (item
->HasProperty("item_start"))
1714 dbItem
.SetProperty("item_start", item
->GetProperty("item_start"));
1715 return IsSamePath(&dbItem
);
1717 if (item
->IsVideoDb() && item
->HasVideoInfoTag())
1719 CFileItem
dbItem(item
->GetVideoInfoTag()->m_strFileNameAndPath
, false);
1720 if (item
->HasProperty("item_start"))
1721 dbItem
.SetProperty("item_start", item
->GetProperty("item_start"));
1722 return IsSamePath(&dbItem
);
1724 if (HasProperty("original_listitem_url"))
1725 return (GetProperty("original_listitem_url") == item
->GetPath());
1729 bool CFileItem::IsAlbum() const
1734 void CFileItem::UpdateInfo(const CFileItem
&item
, bool replaceLabels
/*=true*/)
1736 if (item
.HasVideoInfoTag())
1737 { // copy info across
1738 //! @todo premiered info is normally stored in m_dateTime by the db
1740 if (item
.m_videoInfoTag
)
1743 *m_videoInfoTag
= *item
.m_videoInfoTag
;
1745 m_videoInfoTag
= new CVideoInfoTag(*item
.m_videoInfoTag
);
1750 delete m_videoInfoTag
;
1752 m_videoInfoTag
= new CVideoInfoTag
;
1755 m_pvrRecordingInfoTag
= item
.m_pvrRecordingInfoTag
;
1757 SetOverlayImage(GetVideoInfoTag()->GetPlayCount() > 0 ? CGUIListItem::ICON_OVERLAY_WATCHED
1758 : CGUIListItem::ICON_OVERLAY_UNWATCHED
);
1761 if (item
.HasMusicInfoTag())
1763 *GetMusicInfoTag() = *item
.GetMusicInfoTag();
1766 if (item
.HasPictureInfoTag())
1768 *GetPictureInfoTag() = *item
.GetPictureInfoTag();
1771 if (item
.HasGameInfoTag())
1773 *GetGameInfoTag() = *item
.GetGameInfoTag();
1776 if (item
.HasPVRChannelGroupMemberInfoTag())
1778 m_pvrChannelGroupMemberInfoTag
= item
.GetPVRChannelGroupMemberInfoTag();
1781 if (item
.HasPVRTimerInfoTag())
1783 m_pvrTimerInfoTag
= item
.m_pvrTimerInfoTag
;
1786 if (item
.HasEPGInfoTag())
1788 m_epgInfoTag
= item
.m_epgInfoTag
;
1791 if (item
.HasEPGSearchFilter())
1793 m_epgSearchFilter
= item
.m_epgSearchFilter
;
1796 SetDynPath(item
.GetDynPath());
1797 if (replaceLabels
&& !item
.GetLabel().empty())
1798 SetLabel(item
.GetLabel());
1799 if (replaceLabels
&& !item
.GetLabel2().empty())
1800 SetLabel2(item
.GetLabel2());
1801 if (!item
.GetArt().empty())
1802 SetArt(item
.GetArt());
1803 AppendProperties(item
);
1807 void CFileItem::MergeInfo(const CFileItem
& item
)
1809 // TODO: Currently merge the metadata/art info is implemented for video case only
1810 if (item
.HasVideoInfoTag())
1812 if (item
.m_videoInfoTag
)
1815 m_videoInfoTag
->Merge(*item
.m_videoInfoTag
);
1817 m_videoInfoTag
= new CVideoInfoTag(*item
.m_videoInfoTag
);
1820 m_pvrRecordingInfoTag
= item
.m_pvrRecordingInfoTag
;
1822 SetOverlayImage(GetVideoInfoTag()->GetPlayCount() > 0 ? CGUIListItem::ICON_OVERLAY_WATCHED
1823 : CGUIListItem::ICON_OVERLAY_UNWATCHED
);
1826 if (item
.HasMusicInfoTag())
1828 *GetMusicInfoTag() = *item
.GetMusicInfoTag();
1831 if (item
.HasPictureInfoTag())
1833 *GetPictureInfoTag() = *item
.GetPictureInfoTag();
1836 if (item
.HasGameInfoTag())
1838 *GetGameInfoTag() = *item
.GetGameInfoTag();
1841 if (item
.HasPVRChannelGroupMemberInfoTag())
1843 m_pvrChannelGroupMemberInfoTag
= item
.GetPVRChannelGroupMemberInfoTag();
1846 if (item
.HasPVRTimerInfoTag())
1848 m_pvrTimerInfoTag
= item
.m_pvrTimerInfoTag
;
1851 if (item
.HasEPGInfoTag())
1853 m_epgInfoTag
= item
.m_epgInfoTag
;
1856 if (item
.HasEPGSearchFilter())
1858 m_epgSearchFilter
= item
.m_epgSearchFilter
;
1861 SetDynPath(item
.GetDynPath());
1862 if (!item
.GetLabel().empty())
1863 SetLabel(item
.GetLabel());
1864 if (!item
.GetLabel2().empty())
1865 SetLabel2(item
.GetLabel2());
1866 if (!item
.GetArt().empty())
1869 AppendArt(item
.GetArt());
1871 SetArt(item
.GetArt());
1873 AppendProperties(item
);
1877 void CFileItem::SetFromVideoInfoTag(const CVideoInfoTag
&video
)
1879 if (!video
.m_strTitle
.empty())
1880 SetLabel(video
.m_strTitle
);
1881 if (video
.m_strFileNameAndPath
.empty())
1883 m_strPath
= video
.m_strPath
;
1884 URIUtils::AddSlashAtEnd(m_strPath
);
1889 m_strPath
= video
.m_strFileNameAndPath
;
1890 m_bIsFolder
= false;
1894 *m_videoInfoTag
= video
;
1896 m_videoInfoTag
= new CVideoInfoTag(video
);
1898 if (video
.m_iSeason
== 0)
1899 SetProperty("isspecial", "true");
1900 FillInDefaultIcon();
1901 FillInMimeType(false);
1906 class CPropertySaveHelper
1909 CPropertySaveHelper(CFileItem
& item
, const std::string
& property
, const std::string
& value
)
1910 : m_item(item
), m_property(property
), m_value(value
)
1914 bool NeedsSave() const { return !m_value
.empty() || m_item
.HasProperty(m_property
); }
1916 std::string
GetValueToSave(const std::string
& currentValue
) const
1920 if (!m_value
.empty())
1922 // Overwrite whatever we have; remember what we had originally.
1923 if (!m_item
.HasProperty(m_property
))
1924 m_item
.SetProperty(m_property
, currentValue
);
1928 else if (m_item
.HasProperty(m_property
))
1930 // Restore original value
1931 value
= m_item
.GetProperty(m_property
).asString();
1932 m_item
.ClearProperty(m_property
);
1940 const std::string m_property
;
1941 const std::string m_value
;
1943 } // unnamed namespace
1945 void CFileItem::SetFromMusicInfoTag(const MUSIC_INFO::CMusicInfoTag
& music
)
1947 const std::string path
= GetPath();
1950 SetPath(music
.GetURL());
1954 const CPropertySaveHelper
dynpath(*this, "OriginalDynPath", music
.GetURL());
1955 if (dynpath
.NeedsSave())
1956 SetDynPath(dynpath
.GetValueToSave(m_strDynPath
));
1959 const CPropertySaveHelper
label(*this, "OriginalLabel", music
.GetTitle());
1960 if (label
.NeedsSave())
1961 SetLabel(label
.GetValueToSave(GetLabel()));
1963 const CPropertySaveHelper
thumb(*this, "OriginalThumb", music
.GetStationArt());
1964 if (thumb
.NeedsSave())
1965 SetArt("thumb", thumb
.GetValueToSave(GetArt("thumb")));
1967 *GetMusicInfoTag() = music
;
1968 FillInDefaultIcon();
1969 FillInMimeType(false);
1972 void CFileItem::SetFromAlbum(const CAlbum
&album
)
1974 if (!album
.strAlbum
.empty())
1975 SetLabel(album
.strAlbum
);
1977 m_strLabel2
= album
.GetAlbumArtistString();
1978 GetMusicInfoTag()->SetAlbum(album
);
1980 if (album
.art
.empty())
1981 SetArt("icon", "DefaultAlbumCover.png");
1986 CMusicDatabase::SetPropertiesFromAlbum(*this,album
);
1987 FillInMimeType(false);
1990 void CFileItem::SetFromSong(const CSong
&song
)
1992 if (!song
.strTitle
.empty())
1993 SetLabel(song
.strTitle
);
1994 if (song
.idSong
> 0)
1996 std::string strExt
= URIUtils::GetExtension(song
.strFileName
);
1997 m_strPath
= StringUtils::Format("musicdb://songs/{}{}", song
.idSong
, strExt
);
1999 else if (!song
.strFileName
.empty())
2000 m_strPath
= song
.strFileName
;
2001 GetMusicInfoTag()->SetSong(song
);
2002 m_lStartOffset
= song
.iStartOffset
;
2003 m_lStartPartNumber
= 1;
2004 SetProperty("item_start", song
.iStartOffset
);
2005 m_lEndOffset
= song
.iEndOffset
;
2006 if (!song
.strThumb
.empty())
2007 SetArt("thumb", song
.strThumb
);
2008 FillInMimeType(false);
2011 std::string
CFileItem::GetOpticalMediaPath() const
2014 path
= URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS.IFO");
2015 if (CFile::Exists(path
))
2018 path
= URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS", "VIDEO_TS.IFO");
2019 if (CFile::Exists(path
))
2022 #ifdef HAVE_LIBBLURAY
2023 path
= URIUtils::AddFileToFolder(GetPath(), "index.bdmv");
2024 if (CFile::Exists(path
))
2027 path
= URIUtils::AddFileToFolder(GetPath(), "BDMV", "index.bdmv");
2028 if (CFile::Exists(path
))
2031 path
= URIUtils::AddFileToFolder(GetPath(), "INDEX.BDM");
2032 if (CFile::Exists(path
))
2035 path
= URIUtils::AddFileToFolder(GetPath(), "BDMV", "INDEX.BDM");
2036 if (CFile::Exists(path
))
2039 return std::string();
2043 * @todo Ideally this (and SetPath) would not be available outside of construction
2044 * for CFileItem objects, or at least restricted to essentially be equivalent
2045 * to construction. This would require re-formulating a bunch of CFileItem
2046 * construction, and also allowing CFileItemList to have its own (public)
2047 * SetURL() function, so for now we give direct access.
2049 void CFileItem::SetURL(const CURL
& url
)
2051 m_strPath
= url
.Get();
2054 const CURL
CFileItem::GetURL() const
2056 CURL
url(m_strPath
);
2060 bool CFileItem::IsURL(const CURL
& url
) const
2062 return IsPath(url
.Get());
2065 bool CFileItem::IsPath(const std::string
& path
, bool ignoreURLOptions
/* = false */) const
2067 return URIUtils::PathEquals(m_strPath
, path
, false, ignoreURLOptions
);
2070 void CFileItem::SetDynURL(const CURL
& url
)
2072 m_strDynPath
= url
.Get();
2075 const CURL
CFileItem::GetDynURL() const
2077 if (!m_strDynPath
.empty())
2079 CURL
url(m_strDynPath
);
2084 CURL
url(m_strPath
);
2089 const std::string
&CFileItem::GetDynPath() const
2091 if (!m_strDynPath
.empty())
2092 return m_strDynPath
;
2097 void CFileItem::SetDynPath(const std::string
&path
)
2099 m_strDynPath
= path
;
2102 void CFileItem::SetCueDocument(const CCueDocumentPtr
& cuePtr
)
2104 m_cueDocument
= cuePtr
;
2107 void CFileItem::LoadEmbeddedCue()
2109 CMusicInfoTag
& tag
= *GetMusicInfoTag();
2113 const std::string embeddedCue
= tag
.GetCueSheet();
2114 if (!embeddedCue
.empty())
2116 CCueDocumentPtr
cuesheet(new CCueDocument
);
2117 if (cuesheet
->ParseTag(embeddedCue
))
2119 std::vector
<std::string
> MediaFileVec
;
2120 cuesheet
->GetMediaFiles(MediaFileVec
);
2121 for (std::vector
<std::string
>::iterator itMedia
= MediaFileVec
.begin();
2122 itMedia
!= MediaFileVec
.end(); ++itMedia
)
2123 cuesheet
->UpdateMediaFile(*itMedia
, GetPath());
2124 SetCueDocument(cuesheet
);
2126 // Clear cuesheet tag having added it to item
2127 tag
.SetCueSheet("");
2131 bool CFileItem::HasCueDocument() const
2133 return (m_cueDocument
.get() != nullptr);
2136 bool CFileItem::LoadTracksFromCueDocument(CFileItemList
& scannedItems
)
2141 const CMusicInfoTag
& tag
= *GetMusicInfoTag();
2144 m_cueDocument
->GetSongs(tracks
);
2146 bool oneFilePerTrack
= m_cueDocument
->IsOneFilePerTrack();
2147 m_cueDocument
.reset();
2149 int tracksFound
= 0;
2150 for (VECSONGS::iterator it
= tracks
.begin(); it
!= tracks
.end(); ++it
)
2153 if (song
.strFileName
== GetPath())
2157 if (song
.strAlbum
.empty() && !tag
.GetAlbum().empty())
2158 song
.strAlbum
= tag
.GetAlbum();
2159 //Pass album artist to final MusicInfoTag object via setting song album artist vector.
2160 if (song
.GetAlbumArtist().empty() && !tag
.GetAlbumArtist().empty())
2161 song
.SetAlbumArtist(tag
.GetAlbumArtist());
2162 if (song
.genre
.empty() && !tag
.GetGenre().empty())
2163 song
.genre
= tag
.GetGenre();
2164 //Pass artist to final MusicInfoTag object via setting song artist description string only.
2165 //Artist credits not used during loading from cue sheet.
2166 if (song
.strArtistDesc
.empty() && !tag
.GetArtistString().empty())
2167 song
.strArtistDesc
= tag
.GetArtistString();
2168 if (tag
.GetDiscNumber())
2169 song
.iTrack
|= (tag
.GetDiscNumber() << 16); // see CMusicInfoTag::GetDiscNumber()
2170 if (!tag
.GetCueSheet().empty())
2171 song
.strCueSheet
= tag
.GetCueSheet();
2174 song
.strReleaseDate
= tag
.GetReleaseDate();
2175 if (song
.embeddedArt
.Empty() && !tag
.GetCoverArtInfo().Empty())
2176 song
.embeddedArt
= tag
.GetCoverArtInfo();
2179 if (!song
.iDuration
&& tag
.GetDuration() > 0)
2180 { // must be the last song
2181 song
.iDuration
= CUtil::ConvertMilliSecsToSecsIntRounded(CUtil::ConvertSecsToMilliSecs(tag
.GetDuration()) - song
.iStartOffset
);
2183 if ( tag
.Loaded() && oneFilePerTrack
&& ! ( tag
.GetAlbum().empty() || tag
.GetArtist().empty() || tag
.GetTitle().empty() ) )
2185 // If there are multiple files in a cue file, the tags from the files should be preferred if they exist.
2186 scannedItems
.Add(std::make_shared
<CFileItem
>(song
, tag
));
2190 scannedItems
.Add(std::make_shared
<CFileItem
>(song
));
2195 return tracksFound
!= 0;
2198 /////////////////////////////////////////////////////////////////////////////////
2202 //////////////////////////////////////////////////////////////////////////////////
2204 CFileItemList::CFileItemList()
2205 : CFileItem("", true)
2209 CFileItemList::CFileItemList(const std::string
& strPath
)
2210 : CFileItem(strPath
, true)
2214 CFileItemList::~CFileItemList()
2219 CFileItemPtr
CFileItemList::operator[] (int iItem
)
2224 const CFileItemPtr
CFileItemList::operator[] (int iItem
) const
2229 CFileItemPtr
CFileItemList::operator[] (const std::string
& strPath
)
2231 return Get(strPath
);
2234 const CFileItemPtr
CFileItemList::operator[] (const std::string
& strPath
) const
2236 return Get(strPath
);
2239 void CFileItemList::SetIgnoreURLOptions(bool ignoreURLOptions
)
2241 m_ignoreURLOptions
= ignoreURLOptions
;
2245 m_fastLookup
= false; // Force SetFastlookup to clear map
2246 SetFastLookup(true); // and regenerate map
2250 void CFileItemList::SetFastLookup(bool fastLookup
)
2252 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2254 if (fastLookup
&& !m_fastLookup
)
2255 { // generate the map
2257 for (unsigned int i
=0; i
< m_items
.size(); i
++)
2259 CFileItemPtr pItem
= m_items
[i
];
2260 m_map
.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions
? CURL(pItem
->GetPath()).GetWithoutOptions() : pItem
->GetPath(), pItem
));
2263 if (!fastLookup
&& m_fastLookup
)
2265 m_fastLookup
= fastLookup
;
2268 bool CFileItemList::Contains(const std::string
& fileName
) const
2270 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2273 return m_map
.find(m_ignoreURLOptions
? CURL(fileName
).GetWithoutOptions() : fileName
) != m_map
.end();
2276 for (unsigned int i
= 0; i
< m_items
.size(); i
++)
2278 const CFileItemPtr pItem
= m_items
[i
];
2279 if (pItem
->IsPath(m_ignoreURLOptions
? CURL(fileName
).GetWithoutOptions() : fileName
))
2285 void CFileItemList::Clear()
2287 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2290 m_sortDescription
.sortBy
= SortByNone
;
2291 m_sortDescription
.sortOrder
= SortOrderNone
;
2292 m_sortDescription
.sortAttributes
= SortAttributeNone
;
2293 m_sortIgnoreFolders
= false;
2294 m_cacheToDisc
= CACHE_IF_SLOW
;
2295 m_sortDetails
.clear();
2296 m_replaceListing
= false;
2300 void CFileItemList::ClearItems()
2302 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2303 // make sure we free the memory of the items (these are GUIControls which may have allocated resources)
2305 for (unsigned int i
= 0; i
< m_items
.size(); i
++)
2307 CFileItemPtr item
= m_items
[i
];
2314 void CFileItemList::Add(CFileItemPtr pItem
)
2316 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2318 m_map
.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions
? CURL(pItem
->GetPath()).GetWithoutOptions() : pItem
->GetPath(), pItem
));
2319 m_items
.emplace_back(std::move(pItem
));
2322 void CFileItemList::Add(CFileItem
&& item
)
2324 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2325 auto ptr
= std::make_shared
<CFileItem
>(std::move(item
));
2327 m_map
.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions
? CURL(ptr
->GetPath()).GetWithoutOptions() : ptr
->GetPath(), ptr
));
2328 m_items
.emplace_back(std::move(ptr
));
2331 void CFileItemList::AddFront(const CFileItemPtr
&pItem
, int itemPosition
)
2333 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2335 if (itemPosition
>= 0)
2337 m_items
.insert(m_items
.begin()+itemPosition
, pItem
);
2341 m_items
.insert(m_items
.begin()+(m_items
.size()+itemPosition
), pItem
);
2345 m_map
.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions
? CURL(pItem
->GetPath()).GetWithoutOptions() : pItem
->GetPath(), pItem
));
2349 void CFileItemList::Remove(CFileItem
* pItem
)
2351 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2353 for (IVECFILEITEMS it
= m_items
.begin(); it
!= m_items
.end(); ++it
)
2355 if (pItem
== it
->get())
2360 m_map
.erase(m_ignoreURLOptions
? CURL(pItem
->GetPath()).GetWithoutOptions() : pItem
->GetPath());
2367 VECFILEITEMS::iterator
CFileItemList::erase(VECFILEITEMS::iterator first
,
2368 VECFILEITEMS::iterator last
)
2370 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2371 return m_items
.erase(first
, last
);
2374 void CFileItemList::Remove(int iItem
)
2376 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2378 if (iItem
>= 0 && iItem
< Size())
2380 CFileItemPtr pItem
= *(m_items
.begin() + iItem
);
2383 m_map
.erase(m_ignoreURLOptions
? CURL(pItem
->GetPath()).GetWithoutOptions() : pItem
->GetPath());
2385 m_items
.erase(m_items
.begin() + iItem
);
2389 void CFileItemList::Append(const CFileItemList
& itemlist
)
2391 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2393 for (int i
= 0; i
< itemlist
.Size(); ++i
)
2397 void CFileItemList::Assign(const CFileItemList
& itemlist
, bool append
)
2399 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2403 SetPath(itemlist
.GetPath());
2404 SetLabel(itemlist
.GetLabel());
2405 m_sortDetails
= itemlist
.m_sortDetails
;
2406 m_sortDescription
= itemlist
.m_sortDescription
;
2407 m_replaceListing
= itemlist
.m_replaceListing
;
2408 m_content
= itemlist
.m_content
;
2409 m_mapProperties
= itemlist
.m_mapProperties
;
2410 m_cacheToDisc
= itemlist
.m_cacheToDisc
;
2413 bool CFileItemList::Copy(const CFileItemList
& items
, bool copyItems
/* = true */)
2415 // assign all CFileItem parts
2416 *static_cast<CFileItem
*>(this) = static_cast<const CFileItem
&>(items
);
2418 // assign the rest of the CFileItemList properties
2419 m_replaceListing
= items
.m_replaceListing
;
2420 m_content
= items
.m_content
;
2421 m_mapProperties
= items
.m_mapProperties
;
2422 m_cacheToDisc
= items
.m_cacheToDisc
;
2423 m_sortDetails
= items
.m_sortDetails
;
2424 m_sortDescription
= items
.m_sortDescription
;
2425 m_sortIgnoreFolders
= items
.m_sortIgnoreFolders
;
2429 // make a copy of each item
2430 for (int i
= 0; i
< items
.Size(); i
++)
2432 CFileItemPtr
newItem(new CFileItem(*items
[i
]));
2440 CFileItemPtr
CFileItemList::Get(int iItem
) const
2442 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2444 if (iItem
> -1 && iItem
< (int)m_items
.size())
2445 return m_items
[iItem
];
2447 return CFileItemPtr();
2450 CFileItemPtr
CFileItemList::Get(const std::string
& strPath
) const
2452 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2456 MAPFILEITEMS::const_iterator it
=
2457 m_map
.find(m_ignoreURLOptions
? CURL(strPath
).GetWithoutOptions() : strPath
);
2458 if (it
!= m_map
.end())
2461 return CFileItemPtr();
2464 for (unsigned int i
= 0; i
< m_items
.size(); i
++)
2466 CFileItemPtr pItem
= m_items
[i
];
2467 if (pItem
->IsPath(m_ignoreURLOptions
? CURL(strPath
).GetWithoutOptions() : strPath
))
2471 return CFileItemPtr();
2474 int CFileItemList::Size() const
2476 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2477 return (int)m_items
.size();
2480 bool CFileItemList::IsEmpty() const
2482 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2483 return m_items
.empty();
2486 void CFileItemList::Reserve(size_t iCount
)
2488 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2489 m_items
.reserve(iCount
);
2492 void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func
)
2494 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2495 std::stable_sort(m_items
.begin(), m_items
.end(), func
);
2498 void CFileItemList::FillSortFields(FILEITEMFILLFUNC func
)
2500 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2501 std::for_each(m_items
.begin(), m_items
.end(), func
);
2504 void CFileItemList::Sort(SortBy sortBy
, SortOrder sortOrder
, SortAttribute sortAttributes
/* = SortAttributeNone */)
2506 if (sortBy
== SortByNone
||
2507 (m_sortDescription
.sortBy
== sortBy
&& m_sortDescription
.sortOrder
== sortOrder
&&
2508 m_sortDescription
.sortAttributes
== sortAttributes
))
2511 SortDescription sorting
;
2512 sorting
.sortBy
= sortBy
;
2513 sorting
.sortOrder
= sortOrder
;
2514 sorting
.sortAttributes
= sortAttributes
;
2517 m_sortDescription
= sorting
;
2520 void CFileItemList::Sort(SortDescription sortDescription
)
2522 if (sortDescription
.sortBy
== SortByFile
|| sortDescription
.sortBy
== SortBySortTitle
||
2523 sortDescription
.sortBy
== SortByOriginalTitle
|| sortDescription
.sortBy
== SortByDateAdded
||
2524 sortDescription
.sortBy
== SortByRating
|| sortDescription
.sortBy
== SortByYear
||
2525 sortDescription
.sortBy
== SortByPlaylistOrder
|| sortDescription
.sortBy
== SortByLastPlayed
||
2526 sortDescription
.sortBy
== SortByPlaycount
)
2527 sortDescription
.sortAttributes
= (SortAttribute
)((int)sortDescription
.sortAttributes
| SortAttributeIgnoreFolders
);
2529 if (sortDescription
.sortBy
== SortByNone
||
2530 (m_sortDescription
.sortBy
== sortDescription
.sortBy
&& m_sortDescription
.sortOrder
== sortDescription
.sortOrder
&&
2531 m_sortDescription
.sortAttributes
== sortDescription
.sortAttributes
))
2534 if (m_sortIgnoreFolders
)
2535 sortDescription
.sortAttributes
= (SortAttribute
)((int)sortDescription
.sortAttributes
| SortAttributeIgnoreFolders
);
2537 const Fields fields
= SortUtils::GetFieldsForSorting(sortDescription
.sortBy
);
2538 SortItems
sortItems((size_t)Size());
2539 for (int index
= 0; index
< Size(); index
++)
2541 sortItems
[index
] = std::make_shared
<SortItem
>();
2542 m_items
[index
]->ToSortable(*sortItems
[index
], fields
);
2543 (*sortItems
[index
])[FieldId
] = index
;
2547 SortUtils::Sort(sortDescription
, sortItems
);
2549 // apply the new order to the existing CFileItems
2550 VECFILEITEMS sortedFileItems
;
2551 sortedFileItems
.reserve(Size());
2552 for (SortItems::const_iterator it
= sortItems
.begin(); it
!= sortItems
.end(); ++it
)
2554 CFileItemPtr item
= m_items
[(int)(*it
)->at(FieldId
).asInteger()];
2555 // Set the sort label in the CFileItem
2556 item
->SetSortLabel((*it
)->at(FieldSort
).asWideString());
2558 sortedFileItems
.push_back(item
);
2561 // replace the current list with the re-ordered one
2562 m_items
= std::move(sortedFileItems
);
2565 void CFileItemList::Randomize()
2567 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2568 KODI::UTILS::RandomShuffle(m_items
.begin(), m_items
.end());
2571 void CFileItemList::Archive(CArchive
& ar
)
2573 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2576 CFileItem::Archive(ar
);
2579 if (!m_items
.empty() && m_items
[0]->IsParentFolder())
2582 ar
<< (int)(m_items
.size() - i
);
2584 ar
<< m_ignoreURLOptions
;
2588 ar
<< (int)m_sortDescription
.sortBy
;
2589 ar
<< (int)m_sortDescription
.sortOrder
;
2590 ar
<< (int)m_sortDescription
.sortAttributes
;
2591 ar
<< m_sortIgnoreFolders
;
2592 ar
<< (int)m_cacheToDisc
;
2594 ar
<< (int)m_sortDetails
.size();
2595 for (unsigned int j
= 0; j
< m_sortDetails
.size(); ++j
)
2597 const GUIViewSortDetails
&details
= m_sortDetails
[j
];
2598 ar
<< (int)details
.m_sortDescription
.sortBy
;
2599 ar
<< (int)details
.m_sortDescription
.sortOrder
;
2600 ar
<< (int)details
.m_sortDescription
.sortAttributes
;
2601 ar
<< details
.m_buttonLabel
;
2602 ar
<< details
.m_labelMasks
.m_strLabelFile
;
2603 ar
<< details
.m_labelMasks
.m_strLabelFolder
;
2604 ar
<< details
.m_labelMasks
.m_strLabel2File
;
2605 ar
<< details
.m_labelMasks
.m_strLabel2Folder
;
2610 for (; i
< (int)m_items
.size(); ++i
)
2612 CFileItemPtr pItem
= m_items
[i
];
2618 CFileItemPtr pParent
;
2621 CFileItemPtr pItem
=m_items
[0];
2622 if (pItem
->IsParentFolder())
2623 pParent
= std::make_shared
<CFileItem
>(*pItem
);
2626 SetIgnoreURLOptions(false);
2627 SetFastLookup(false);
2630 CFileItem::Archive(ar
);
2639 m_items
.reserve(iSize
+ 1);
2640 m_items
.push_back(pParent
);
2643 m_items
.reserve(iSize
);
2645 bool ignoreURLOptions
= false;
2646 ar
>> ignoreURLOptions
;
2648 bool fastLookup
= false;
2653 m_sortDescription
.sortBy
= (SortBy
)tempint
;
2655 m_sortDescription
.sortOrder
= (SortOrder
)tempint
;
2657 m_sortDescription
.sortAttributes
= (SortAttribute
)tempint
;
2658 ar
>> m_sortIgnoreFolders
;
2660 m_cacheToDisc
= CACHE_TYPE(tempint
);
2662 unsigned int detailSize
= 0;
2664 for (unsigned int j
= 0; j
< detailSize
; ++j
)
2666 GUIViewSortDetails details
;
2668 details
.m_sortDescription
.sortBy
= (SortBy
)tempint
;
2670 details
.m_sortDescription
.sortOrder
= (SortOrder
)tempint
;
2672 details
.m_sortDescription
.sortAttributes
= (SortAttribute
)tempint
;
2673 ar
>> details
.m_buttonLabel
;
2674 ar
>> details
.m_labelMasks
.m_strLabelFile
;
2675 ar
>> details
.m_labelMasks
.m_strLabelFolder
;
2676 ar
>> details
.m_labelMasks
.m_strLabel2File
;
2677 ar
>> details
.m_labelMasks
.m_strLabel2Folder
;
2678 m_sortDetails
.push_back(details
);
2683 for (int i
= 0; i
< iSize
; ++i
)
2685 CFileItemPtr
pItem(new CFileItem
);
2690 SetIgnoreURLOptions(ignoreURLOptions
);
2691 SetFastLookup(fastLookup
);
2695 void CFileItemList::FillInDefaultIcons()
2697 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2698 for (int i
= 0; i
< (int)m_items
.size(); ++i
)
2700 CFileItemPtr pItem
= m_items
[i
];
2701 pItem
->FillInDefaultIcon();
2705 int CFileItemList::GetFolderCount() const
2707 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2708 int nFolderCount
= 0;
2709 for (int i
= 0; i
< (int)m_items
.size(); i
++)
2711 CFileItemPtr pItem
= m_items
[i
];
2712 if (pItem
->m_bIsFolder
)
2716 return nFolderCount
;
2719 int CFileItemList::GetObjectCount() const
2721 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2723 int numObjects
= (int)m_items
.size();
2724 if (numObjects
&& m_items
[0]->IsParentFolder())
2730 int CFileItemList::GetFileCount() const
2732 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2734 for (int i
= 0; i
< (int)m_items
.size(); i
++)
2736 CFileItemPtr pItem
= m_items
[i
];
2737 if (!pItem
->m_bIsFolder
)
2744 int CFileItemList::GetSelectedCount() const
2746 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2748 for (int i
= 0; i
< (int)m_items
.size(); i
++)
2750 CFileItemPtr pItem
= m_items
[i
];
2751 if (pItem
->IsSelected())
2758 void CFileItemList::FilterCueItems()
2760 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2761 // Handle .CUE sheet files...
2762 std::vector
<std::string
> itemstodelete
;
2763 for (int i
= 0; i
< (int)m_items
.size(); i
++)
2765 CFileItemPtr pItem
= m_items
[i
];
2766 if (!pItem
->m_bIsFolder
)
2767 { // see if it's a .CUE sheet
2768 if (pItem
->IsCUESheet())
2770 CCueDocumentPtr
cuesheet(new CCueDocument
);
2771 if (cuesheet
->ParseFile(pItem
->GetPath()))
2773 std::vector
<std::string
> MediaFileVec
;
2774 cuesheet
->GetMediaFiles(MediaFileVec
);
2776 // queue the cue sheet and the underlying media file for deletion
2777 for (std::vector
<std::string
>::iterator itMedia
= MediaFileVec
.begin();
2778 itMedia
!= MediaFileVec
.end(); ++itMedia
)
2780 std::string strMediaFile
= *itMedia
;
2781 std::string fileFromCue
= strMediaFile
; // save the file from the cue we're matching against,
2782 // as we're going to search for others here...
2783 bool bFoundMediaFile
= CFile::Exists(strMediaFile
);
2784 if (!bFoundMediaFile
)
2786 // try file in same dir, not matching case...
2787 if (Contains(strMediaFile
))
2789 bFoundMediaFile
= true;
2793 // try removing the .cue extension...
2794 strMediaFile
= pItem
->GetPath();
2795 URIUtils::RemoveExtension(strMediaFile
);
2796 CFileItem
item(strMediaFile
, false);
2797 if (item
.IsAudio() && Contains(strMediaFile
))
2799 bFoundMediaFile
= true;
2802 { // try replacing the extension with one of our allowed ones.
2803 std::vector
<std::string
> extensions
= StringUtils::Split(CServiceBroker::GetFileExtensionProvider().GetMusicExtensions(), "|");
2804 for (std::vector
<std::string
>::const_iterator i
= extensions
.begin(); i
!= extensions
.end(); ++i
)
2806 strMediaFile
= URIUtils::ReplaceExtension(pItem
->GetPath(), *i
);
2807 CFileItem
item(strMediaFile
, false);
2808 if (!item
.IsCUESheet() && !item
.IsPlayList() && Contains(strMediaFile
))
2810 bFoundMediaFile
= true;
2817 if (bFoundMediaFile
)
2819 cuesheet
->UpdateMediaFile(fileFromCue
, strMediaFile
);
2820 // apply CUE for later processing
2821 for (int j
= 0; j
< (int)m_items
.size(); j
++)
2823 CFileItemPtr pItem
= m_items
[j
];
2824 if (StringUtils::CompareNoCase(pItem
->GetPath(), strMediaFile
) == 0)
2825 pItem
->SetCueDocument(cuesheet
);
2830 itemstodelete
.push_back(pItem
->GetPath());
2834 // now delete the .CUE files.
2835 for (int i
= 0; i
< (int)itemstodelete
.size(); i
++)
2837 for (int j
= 0; j
< (int)m_items
.size(); j
++)
2839 CFileItemPtr pItem
= m_items
[j
];
2840 if (StringUtils::CompareNoCase(pItem
->GetPath(), itemstodelete
[i
]) == 0)
2841 { // delete this item
2842 m_items
.erase(m_items
.begin() + j
);
2849 // Remove the extensions from the filenames
2850 void CFileItemList::RemoveExtensions()
2852 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2853 for (int i
= 0; i
< Size(); ++i
)
2854 m_items
[i
]->RemoveExtension();
2857 void CFileItemList::Stack(bool stackFiles
/* = true */)
2859 std::unique_lock
<CCriticalSection
> lock(m_lock
);
2862 if (IsVirtualDirectoryRoot() ||
2868 SetProperty("isstacked", true);
2870 // items needs to be sorted for stuff below to work properly
2871 Sort(SortByLabel
, SortOrderAscending
);
2879 void CFileItemList::StackFolders()
2881 // Precompile our REs
2882 VECCREGEXP folderRegExps
;
2883 CRegExp
folderRegExp(true, CRegExp::autoUtf8
);
2884 const std::vector
<std::string
>& strFolderRegExps
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_folderStackRegExps
;
2886 std::vector
<std::string
>::const_iterator strExpression
= strFolderRegExps
.begin();
2887 while (strExpression
!= strFolderRegExps
.end())
2889 if (!folderRegExp
.RegComp(*strExpression
))
2890 CLog::Log(LOGERROR
, "{}: Invalid folder stack RegExp:'{}'", __FUNCTION__
,
2891 strExpression
->c_str());
2893 folderRegExps
.push_back(folderRegExp
);
2898 if (!folderRegExp
.IsCompiled())
2900 CLog::Log(LOGDEBUG
, "{}: No stack expressions available. Skipping folder stacking",
2906 for (int i
= 0; i
< Size(); i
++)
2908 CFileItemPtr item
= Get(i
);
2909 // combined the folder checks
2910 if (item
->m_bIsFolder
)
2912 // only check known fast sources?
2914 // 1. rars and zips may be on slow sources? is this supposed to be allowed?
2915 if( !item
->IsRemote()
2918 || URIUtils::IsInRAR(item
->GetPath())
2919 || URIUtils::IsInZIP(item
->GetPath())
2920 || URIUtils::IsOnLAN(item
->GetPath())
2923 // stack cd# folders if contains only a single video file
2927 VECCREGEXP::iterator expr
= folderRegExps
.begin();
2928 while (!bMatch
&& expr
!= folderRegExps
.end())
2930 //CLog::Log(LOGDEBUG,"{}: Running expression {} on {}", __FUNCTION__, expr->GetPattern(), item->GetLabel());
2931 bMatch
= (expr
->RegFind(item
->GetLabel().c_str()) != -1);
2934 CFileItemList items
;
2935 CDirectory::GetDirectory(item
->GetPath(), items
,
2936 CServiceBroker::GetFileExtensionProvider().GetVideoExtensions(),
2938 // optimized to only traverse listing once by checking for filecount
2939 // and recording last file item for later use
2942 for (int j
= 0; j
< items
.Size(); j
++)
2944 if (!items
[j
]->m_bIsFolder
)
2955 *item
= *items
[index
];
2960 // check for dvd folders
2963 std::string dvdPath
= item
->GetOpticalMediaPath();
2965 if (!dvdPath
.empty())
2967 // NOTE: should this be done for the CD# folders too?
2968 item
->m_bIsFolder
= false;
2969 item
->SetPath(dvdPath
);
2970 item
->SetLabel2("");
2971 item
->SetLabelPreformatted(true);
2972 m_sortDescription
.sortBy
= SortByNone
; /* sorting is now broken */
2980 void CFileItemList::StackFiles()
2982 // Precompile our REs
2983 VECCREGEXP stackRegExps
;
2984 CRegExp
tmpRegExp(true, CRegExp::autoUtf8
);
2985 const std::vector
<std::string
>& strStackRegExps
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoStackRegExps
;
2986 std::vector
<std::string
>::const_iterator strRegExp
= strStackRegExps
.begin();
2987 while (strRegExp
!= strStackRegExps
.end())
2989 if (tmpRegExp
.RegComp(*strRegExp
))
2991 if (tmpRegExp
.GetCaptureTotal() == 4)
2992 stackRegExps
.push_back(tmpRegExp
);
2994 CLog::Log(LOGERROR
, "Invalid video stack RE ({}). Must have 4 captures.", *strRegExp
);
2999 // now stack the files, some of which may be from the previous stack iteration
3003 CFileItemPtr item1
= Get(i
);
3005 // skip folders, nfo files, playlists
3006 if (item1
->m_bIsFolder
3007 || item1
->IsParentFolder()
3009 || item1
->IsPlayList()
3019 std::string stackName
;
3021 std::string filePath
;
3022 std::vector
<int> stack
;
3023 VECCREGEXP::iterator expr
= stackRegExps
.begin();
3025 URIUtils::Split(item1
->GetPath(), filePath
, file1
);
3026 if (URIUtils::HasEncodedFilename(CURL(filePath
)))
3027 file1
= CURL::Decode(file1
);
3030 while (expr
!= stackRegExps
.end())
3032 if (expr
->RegFind(file1
, offset
) != -1)
3034 std::string Title1
= expr
->GetMatch(1),
3035 Volume1
= expr
->GetMatch(2),
3036 Ignore1
= expr
->GetMatch(3),
3037 Extension1
= expr
->GetMatch(4);
3039 Title1
= file1
.substr(0, expr
->GetSubStart(2));
3043 CFileItemPtr item2
= Get(j
);
3045 // skip folders, nfo files, playlists
3046 if (item2
->m_bIsFolder
3047 || item2
->IsParentFolder()
3049 || item2
->IsPlayList()
3057 std::string file2
, filePath2
;
3058 URIUtils::Split(item2
->GetPath(), filePath2
, file2
);
3059 if (URIUtils::HasEncodedFilename(CURL(filePath2
)) )
3060 file2
= CURL::Decode(file2
);
3062 if (expr
->RegFind(file2
, offset
) != -1)
3064 std::string Title2
= expr
->GetMatch(1),
3065 Volume2
= expr
->GetMatch(2),
3066 Ignore2
= expr
->GetMatch(3),
3067 Extension2
= expr
->GetMatch(4);
3069 Title2
= file2
.substr(0, expr
->GetSubStart(2));
3070 if (StringUtils::EqualsNoCase(Title1
, Title2
))
3072 if (!StringUtils::EqualsNoCase(Volume1
, Volume2
))
3074 if (StringUtils::EqualsNoCase(Ignore1
, Ignore2
) &&
3075 StringUtils::EqualsNoCase(Extension1
, Extension2
))
3079 stackName
= Title1
+ Ignore1
+ Extension1
;
3081 size
+= item1
->m_dwSize
;
3084 size
+= item2
->m_dwSize
;
3093 else if (!StringUtils::EqualsNoCase(Ignore1
, Ignore2
)) // False positive, try again with offset
3095 offset
= expr
->GetSubStart(3);
3098 else // Extension mismatch
3105 else // Title mismatch
3112 else // No match 2, next expression
3121 expr
= stackRegExps
.end();
3128 if (stack
.size() > 1)
3130 // have a stack, remove the items and add the stacked item
3131 // dont actually stack a multipart rar set, just remove all items but the first
3132 std::string stackPath
;
3133 if (Get(stack
[0])->IsRAR())
3134 stackPath
= Get(stack
[0])->GetPath();
3137 CStackDirectory dir
;
3138 stackPath
= dir
.ConstructStackPath(*this, stack
);
3140 item1
->SetPath(stackPath
);
3142 for (unsigned k
= 1; k
< stack
.size(); k
++)
3144 // item->m_bIsFolder = true; // don't treat stacked files as folders
3145 // the label may be in a different char set from the filename (eg over smb
3146 // the label is converted from utf8, but the filename is not)
3147 if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWEXTENSIONS
))
3148 URIUtils::RemoveExtension(stackName
);
3150 item1
->SetLabel(stackName
);
3151 item1
->m_dwSize
= size
;
3159 bool CFileItemList::Load(int windowID
)
3162 auto path
= GetDiscFileCache(windowID
);
3165 if (file
.Open(path
))
3167 CArchive
ar(&file
, CArchive::load
);
3169 CLog::Log(LOGDEBUG
, "Loading items: {}, directory: {} sort method: {}, ascending: {}", Size(),
3170 CURL::GetRedacted(GetPath()), m_sortDescription
.sortBy
,
3171 m_sortDescription
.sortOrder
== SortOrderAscending
? "true" : "false");
3177 catch(const std::out_of_range
&)
3179 CLog::Log(LOGERROR
, "Corrupt archive: {}", CURL::GetRedacted(path
));
3185 bool CFileItemList::Save(int windowID
)
3191 CLog::Log(LOGDEBUG
, "Saving fileitems [{}]", CURL::GetRedacted(GetPath()));
3194 std::string cachefile
= GetDiscFileCache(windowID
);
3195 if (file
.OpenForWrite(cachefile
, true)) // overwrite always
3197 // Before caching save simplified cache file name in every item so the cache file can be
3198 // identifed and removed if the item is updated. List path and options (used for file
3199 // name when list cached) can not be accurately derived from item path.
3200 StringUtils::Replace(cachefile
, "special://temp/archive_cache/", "");
3201 StringUtils::Replace(cachefile
, ".fi", "");
3202 for (const auto& item
: m_items
)
3203 item
->SetProperty("cachefilename", cachefile
);
3205 CArchive
ar(&file
, CArchive::store
);
3207 CLog::Log(LOGDEBUG
, " -- items: {}, sort method: {}, ascending: {}", iSize
,
3208 m_sortDescription
.sortBy
,
3209 m_sortDescription
.sortOrder
== SortOrderAscending
? "true" : "false");
3218 void CFileItemList::RemoveDiscCache(int windowID
) const
3220 RemoveDiscCache(GetDiscFileCache(windowID
));
3223 void CFileItemList::RemoveDiscCache(const std::string
& cacheFile
) const
3225 if (CFile::Exists(cacheFile
))
3227 CLog::Log(LOGDEBUG
, "Clearing cached fileitems [{}]", CURL::GetRedacted(GetPath()));
3228 CFile::Delete(cacheFile
);
3232 void CFileItemList::RemoveDiscCacheCRC(const std::string
& crc
) const
3234 std::string cachefile
= StringUtils::Format("special://temp/archive_cache/{}.fi", crc
);
3235 RemoveDiscCache(cachefile
);
3238 std::string
CFileItemList::GetDiscFileCache(int windowID
) const
3240 std::string
strPath(GetPath());
3241 URIUtils::RemoveSlashAtEnd(strPath
);
3243 uint32_t crc
= Crc32::ComputeFromLowerCase(strPath
);
3245 if (IsCDDA() || IsOnDVD())
3246 return StringUtils::Format("special://temp/archive_cache/r-{:08x}.fi", crc
);
3249 return StringUtils::Format("special://temp/archive_cache/mdb-{:08x}.fi", crc
);
3252 return StringUtils::Format("special://temp/archive_cache/vdb-{:08x}.fi", crc
);
3254 if (IsSmartPlayList())
3255 return StringUtils::Format("special://temp/archive_cache/sp-{:08x}.fi", crc
);
3258 return StringUtils::Format("special://temp/archive_cache/{}-{:08x}.fi", windowID
, crc
);
3260 return StringUtils::Format("special://temp/archive_cache/{:08x}.fi", crc
);
3263 bool CFileItemList::AlwaysCache() const
3265 // some database folders are always cached
3267 return CMusicDatabaseDirectory::CanCache(GetPath());
3269 return CVideoDatabaseDirectory::CanCache(GetPath());
3271 return true; // always cache
3275 std::string
CFileItem::GetUserMusicThumb(bool alwaysCheckRemote
/* = false */, bool fallbackToFolder
/* = false */) const
3277 if (m_strPath
.empty()
3278 || StringUtils::StartsWithNoCase(m_strPath
, "newsmartplaylist://")
3279 || StringUtils::StartsWithNoCase(m_strPath
, "newplaylist://")
3280 || m_bIsShareOrDrive
3281 || IsInternetStream()
3282 || URIUtils::IsUPnP(m_strPath
)
3283 || (URIUtils::IsFTP(m_strPath
) && !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs
)
3286 || IsLibraryFolder()
3291 // we first check for <filename>.tbn or <foldername>.tbn
3292 std::string
fileThumb(GetTBNFile());
3293 if (CFile::Exists(fileThumb
))
3296 // Fall back to folder thumb, if requested
3297 if (!m_bIsFolder
&& fallbackToFolder
)
3299 CFileItem
item(URIUtils::GetDirectory(m_strPath
), true);
3300 return item
.GetUserMusicThumb(alwaysCheckRemote
);
3303 // if a folder, check for folder.jpg
3304 if (m_bIsFolder
&& !IsFileFolder() && (!IsRemote() || alwaysCheckRemote
|| CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MUSICFILES_FINDREMOTETHUMBS
)))
3306 std::vector
<CVariant
> thumbs
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetList(
3307 CSettings::SETTING_MUSICLIBRARY_MUSICTHUMBS
);
3308 for (const auto& i
: thumbs
)
3310 std::string strFileName
= i
.asString();
3311 std::string
folderThumb(GetFolderThumb(strFileName
));
3312 if (CFile::Exists(folderThumb
)) // folder.jpg
3314 size_t period
= strFileName
.find_last_of('.');
3315 if (period
!= std::string::npos
)
3318 std::string name
= strFileName
;
3319 std::string folderThumb1
= folderThumb
;
3321 ext
= strFileName
.substr(period
);
3322 StringUtils::ToUpper(ext
);
3323 StringUtils::Replace(folderThumb1
, strFileName
, name
+ ext
);
3324 if (CFile::Exists(folderThumb1
)) // folder.JPG
3325 return folderThumb1
;
3327 folderThumb1
= folderThumb
;
3328 std::string firstletter
= name
.substr(0, 1);
3329 StringUtils::ToUpper(firstletter
);
3330 name
.replace(0, 1, firstletter
);
3331 StringUtils::Replace(folderThumb1
, strFileName
, name
+ ext
);
3332 if (CFile::Exists(folderThumb1
)) // Folder.JPG
3333 return folderThumb1
;
3335 folderThumb1
= folderThumb
;
3336 StringUtils::ToLower(ext
);
3337 StringUtils::Replace(folderThumb1
, strFileName
, name
+ ext
);
3338 if (CFile::Exists(folderThumb1
)) // Folder.jpg
3339 return folderThumb1
;
3347 // Gets the .tbn filename from a file or folder name.
3348 // <filename>.ext -> <filename>.tbn
3349 // <foldername>/ -> <foldername>.tbn
3350 std::string
CFileItem::GetTBNFile() const
3352 std::string thumbFile
;
3353 std::string strFile
= m_strPath
;
3357 std::string strPath
, strReturn
;
3358 URIUtils::GetParentPath(m_strPath
,strPath
);
3359 CFileItem
item(CStackDirectory::GetFirstStackedFile(strFile
),false);
3360 std::string strTBNFile
= item
.GetTBNFile();
3361 strReturn
= URIUtils::AddFileToFolder(strPath
, URIUtils::GetFileName(strTBNFile
));
3362 if (CFile::Exists(strReturn
))
3365 strFile
= URIUtils::AddFileToFolder(strPath
,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile
)));
3368 if (URIUtils::IsInRAR(strFile
) || URIUtils::IsInZIP(strFile
))
3370 std::string strPath
= URIUtils::GetDirectory(strFile
);
3371 std::string strParent
;
3372 URIUtils::GetParentPath(strPath
,strParent
);
3373 strFile
= URIUtils::AddFileToFolder(strParent
, URIUtils::GetFileName(m_strPath
));
3377 strFile
= url
.GetFileName();
3379 if (m_bIsFolder
&& !IsFileFolder())
3380 URIUtils::RemoveSlashAtEnd(strFile
);
3382 if (!strFile
.empty())
3384 if (m_bIsFolder
&& !IsFileFolder())
3385 thumbFile
= strFile
+ ".tbn"; // folder, so just add ".tbn"
3387 thumbFile
= URIUtils::ReplaceExtension(strFile
, ".tbn");
3388 url
.SetFileName(thumbFile
);
3389 thumbFile
= url
.Get();
3394 bool CFileItem::SkipLocalArt() const
3396 return (m_strPath
.empty()
3397 || StringUtils::StartsWithNoCase(m_strPath
, "newsmartplaylist://")
3398 || StringUtils::StartsWithNoCase(m_strPath
, "newplaylist://")
3399 || m_bIsShareOrDrive
3400 || IsInternetStream()
3401 || URIUtils::IsUPnP(m_strPath
)
3402 || (URIUtils::IsFTP(m_strPath
) && !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs
)
3405 || IsLibraryFolder()
3412 std::string
CFileItem::GetThumbHideIfUnwatched(const CFileItem
* item
) const
3414 const std::shared_ptr
<CSettingList
> setting(std::dynamic_pointer_cast
<CSettingList
>(
3415 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(
3416 CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS
)));
3417 if (setting
&& item
->HasVideoInfoTag() && item
->GetVideoInfoTag()->m_type
== MediaTypeEpisode
&&
3418 item
->GetVideoInfoTag()->GetPlayCount() == 0 &&
3419 !CSettingUtils::FindIntInList(setting
,
3420 CSettings::VIDEOLIBRARY_THUMB_SHOW_UNWATCHED_EPISODE
) &&
3421 item
->HasArt("thumb"))
3423 std::string fanArt
= item
->GetArt("fanart");
3425 return "OverlaySpoiler.png";
3430 return item
->GetArt("thumb");
3433 std::string
CFileItem::FindLocalArt(const std::string
&artFile
, bool useFolder
) const
3441 thumb
= GetLocalArt(artFile
, false);
3442 if (!thumb
.empty() && CFile::Exists(thumb
))
3445 if ((useFolder
|| (m_bIsFolder
&& !IsFileFolder())) && !artFile
.empty())
3447 std::string thumb2
= GetLocalArt(artFile
, true);
3448 if (!thumb2
.empty() && thumb2
!= thumb
&& CFile::Exists(thumb2
))
3454 std::string
CFileItem::GetLocalArtBaseFilename() const
3456 bool useFolder
= false;
3457 return GetLocalArtBaseFilename(useFolder
);
3460 std::string
CFileItem::GetLocalArtBaseFilename(bool& useFolder
) const
3462 std::string strFile
;
3465 std::string strPath
;
3466 URIUtils::GetParentPath(m_strPath
,strPath
);
3467 strFile
= URIUtils::AddFileToFolder(
3468 strPath
, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(m_strPath
)));
3471 std::string file
= strFile
.empty() ? m_strPath
: strFile
;
3472 if (URIUtils::IsInRAR(file
) || URIUtils::IsInZIP(file
))
3474 std::string strPath
= URIUtils::GetDirectory(file
);
3475 std::string strParent
;
3476 URIUtils::GetParentPath(strPath
,strParent
);
3477 strFile
= URIUtils::AddFileToFolder(strParent
, URIUtils::GetFileName(file
));
3481 strFile
= CMultiPathDirectory::GetFirstPath(m_strPath
);
3483 if (IsOpticalMediaFile())
3484 { // optical media files should be treated like folders
3486 strFile
= GetLocalMetadataPath();
3488 else if (useFolder
&& !(m_bIsFolder
&& !IsFileFolder()))
3490 file
= strFile
.empty() ? m_strPath
: strFile
;
3491 strFile
= URIUtils::GetDirectory(file
);
3494 if (strFile
.empty())
3495 strFile
= GetDynPath();
3500 std::string
CFileItem::GetLocalArt(const std::string
& artFile
, bool useFolder
) const
3502 // no retrieving of empty art files from folders
3503 if (useFolder
&& artFile
.empty())
3506 std::string strFile
= GetLocalArtBaseFilename(useFolder
);
3507 if (strFile
.empty()) // empty filepath -> nothing to find
3512 if (!artFile
.empty())
3513 return URIUtils::AddFileToFolder(strFile
, artFile
);
3517 if (artFile
.empty()) // old thumbnail matching
3518 return URIUtils::ReplaceExtension(strFile
, ".tbn");
3520 return URIUtils::ReplaceExtension(strFile
, "-" + artFile
);
3525 std::string
CFileItem::GetFolderThumb(const std::string
&folderJPG
/* = "folder.jpg" */) const
3527 std::string strFolder
= m_strPath
;
3530 URIUtils::IsInRAR(strFolder
) ||
3531 URIUtils::IsInZIP(strFolder
))
3533 URIUtils::GetParentPath(m_strPath
,strFolder
);
3537 strFolder
= CMultiPathDirectory::GetFirstPath(m_strPath
);
3542 return URIUtils::AddFileToFolder(strFolder
, folderJPG
);
3545 std::string
CFileItem::GetMovieName(bool bUseFolderNames
/* = false */) const
3547 if (IsPlugin() && HasVideoInfoTag() && !GetVideoInfoTag()->m_strTitle
.empty())
3548 return GetVideoInfoTag()->m_strTitle
;
3550 if (IsLabelPreformatted())
3553 if (m_pvrRecordingInfoTag
)
3554 return m_pvrRecordingInfoTag
->m_strTitle
;
3555 else if (URIUtils::IsPVRRecording(m_strPath
))
3557 std::string title
= CPVRRecording::GetTitleFromURL(m_strPath
);
3562 std::string strMovieName
;
3563 if (URIUtils::IsStack(m_strPath
))
3564 strMovieName
= CStackDirectory::GetStackedTitlePath(m_strPath
);
3566 strMovieName
= GetBaseMoviePath(bUseFolderNames
);
3568 URIUtils::RemoveSlashAtEnd(strMovieName
);
3570 return CURL::Decode(URIUtils::GetFileName(strMovieName
));
3573 std::string
CFileItem::GetBaseMoviePath(bool bUseFolderNames
) const
3575 std::string strMovieName
= m_strPath
;
3578 strMovieName
= CMultiPathDirectory::GetFirstPath(m_strPath
);
3580 if (IsOpticalMediaFile())
3581 return GetLocalMetadataPath();
3583 if (bUseFolderNames
&&
3584 (!m_bIsFolder
|| URIUtils::IsInArchive(m_strPath
) ||
3585 (HasVideoInfoTag() && GetVideoInfoTag()->m_iDbId
> 0 && !CMediaTypes::IsContainer(GetVideoInfoTag()->m_type
))))
3587 std::string
name2(strMovieName
);
3588 URIUtils::GetParentPath(name2
,strMovieName
);
3589 if (URIUtils::IsInArchive(m_strPath
))
3591 // Try to get archive itself, if empty take path before
3592 name2
= CURL(m_strPath
).GetHostName();
3594 name2
= strMovieName
;
3596 URIUtils::GetParentPath(name2
, strMovieName
);
3599 // Remove trailing 'Disc n' path segment to get actual movie title
3600 strMovieName
= CUtil::RemoveTrailingDiscNumberSegmentFromPath(strMovieName
);
3603 return strMovieName
;
3606 std::string
CFileItem::GetLocalFanart() const
3610 if (!HasVideoInfoTag())
3611 return ""; // nothing can be done
3612 CFileItem
dbItem(m_bIsFolder
? GetVideoInfoTag()->m_strPath
: GetVideoInfoTag()->m_strFileNameAndPath
, m_bIsFolder
);
3613 return dbItem
.GetLocalFanart();
3616 std::string strFile2
;
3617 std::string strFile
= m_strPath
;
3620 std::string strPath
;
3621 URIUtils::GetParentPath(m_strPath
,strPath
);
3622 CStackDirectory dir
;
3623 std::string strPath2
;
3624 strPath2
= dir
.GetStackedTitlePath(strFile
);
3625 strFile
= URIUtils::AddFileToFolder(strPath
, URIUtils::GetFileName(strPath2
));
3626 CFileItem
item(dir
.GetFirstStackedFile(m_strPath
),false);
3627 std::string
strTBNFile(URIUtils::ReplaceExtension(item
.GetTBNFile(), "-fanart"));
3628 strFile2
= URIUtils::AddFileToFolder(strPath
, URIUtils::GetFileName(strTBNFile
));
3630 if (URIUtils::IsInRAR(strFile
) || URIUtils::IsInZIP(strFile
))
3632 std::string strPath
= URIUtils::GetDirectory(strFile
);
3633 std::string strParent
;
3634 URIUtils::GetParentPath(strPath
,strParent
);
3635 strFile
= URIUtils::AddFileToFolder(strParent
, URIUtils::GetFileName(m_strPath
));
3638 // no local fanart available for these
3639 if (IsInternetStream()
3640 || URIUtils::IsUPnP(strFile
)
3641 || URIUtils::IsBluray(strFile
)
3646 || (URIUtils::IsFTP(strFile
) && !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs
)
3647 || m_strPath
.empty())
3650 std::string strDir
= URIUtils::GetDirectory(strFile
);
3655 CFileItemList items
;
3656 CDirectory::GetDirectory(strDir
, items
, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS
| DIR_FLAG_READ_CACHE
| DIR_FLAG_NO_FILE_INFO
);
3657 if (IsOpticalMediaFile())
3658 { // grab from the optical media parent folder as well
3659 CFileItemList moreItems
;
3660 CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems
, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), DIR_FLAG_NO_FILE_DIRS
| DIR_FLAG_READ_CACHE
| DIR_FLAG_NO_FILE_INFO
);
3661 items
.Append(moreItems
);
3664 std::vector
<std::string
> fanarts
= { "fanart" };
3666 strFile
= URIUtils::ReplaceExtension(strFile
, "-fanart");
3667 fanarts
.insert(m_bIsFolder
? fanarts
.end() : fanarts
.begin(), URIUtils::GetFileName(strFile
));
3669 if (!strFile2
.empty())
3670 fanarts
.insert(m_bIsFolder
? fanarts
.end() : fanarts
.begin(), URIUtils::GetFileName(strFile2
));
3672 for (std::vector
<std::string
>::const_iterator i
= fanarts
.begin(); i
!= fanarts
.end(); ++i
)
3674 for (int j
= 0; j
< items
.Size(); j
++)
3676 std::string strCandidate
= URIUtils::GetFileName(items
[j
]->m_strPath
);
3677 URIUtils::RemoveExtension(strCandidate
);
3678 std::string strFanart
= *i
;
3679 URIUtils::RemoveExtension(strFanart
);
3680 if (StringUtils::EqualsNoCase(strCandidate
, strFanart
))
3681 return items
[j
]->m_strPath
;
3688 std::string
CFileItem::GetLocalMetadataPath() const
3690 if (m_bIsFolder
&& !IsFileFolder())
3693 std::string
parent(URIUtils::GetParentPath(m_strPath
));
3694 std::string
parentFolder(parent
);
3695 URIUtils::RemoveSlashAtEnd(parentFolder
);
3696 parentFolder
= URIUtils::GetFileName(parentFolder
);
3697 if (StringUtils::EqualsNoCase(parentFolder
, "VIDEO_TS") || StringUtils::EqualsNoCase(parentFolder
, "BDMV"))
3698 { // go back up another one
3699 parent
= URIUtils::GetParentPath(parent
);
3704 bool CFileItem::LoadMusicTag()
3710 if (HasMusicInfoTag() && m_musicInfoTag
->Loaded())
3713 CMusicDatabase musicDatabase
;
3714 if (musicDatabase
.Open())
3717 if (musicDatabase
.GetSongByFileName(m_strPath
, song
))
3719 GetMusicInfoTag()->SetSong(song
);
3722 musicDatabase
.Close();
3724 // load tag from file
3725 CLog::Log(LOGDEBUG
, "{}: loading tag information for file: {}", __FUNCTION__
, m_strPath
);
3726 CMusicInfoTagLoaderFactory factory
;
3727 std::unique_ptr
<IMusicInfoTagLoader
> pLoader (factory
.CreateLoader(*this));
3730 if (pLoader
->Load(m_strPath
, *GetMusicInfoTag()))
3733 // no tag - try some other things
3736 // we have the tracknumber...
3737 int iTrack
= GetMusicInfoTag()->GetTrackNumber();
3740 std::string strText
= g_localizeStrings
.Get(554); // "Track"
3741 if (!strText
.empty() && strText
[strText
.size() - 1] != ' ')
3743 std::string strTrack
= StringUtils::Format((strText
+ "{}"), iTrack
);
3744 GetMusicInfoTag()->SetTitle(strTrack
);
3745 GetMusicInfoTag()->SetLoaded(true);
3751 std::string fileName
= URIUtils::GetFileName(m_strPath
);
3752 URIUtils::RemoveExtension(fileName
);
3753 for (const std::string
& fileFilter
: CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicTagsFromFileFilters
)
3755 CLabelFormatter
formatter(fileFilter
, "");
3756 if (formatter
.FillMusicTag(fileName
, GetMusicInfoTag()))
3758 GetMusicInfoTag()->SetLoaded(true);
3766 bool CFileItem::LoadGameTag()
3769 if (HasGameInfoTag() && m_gameInfoTag
->IsLoaded())
3775 m_gameInfoTag
->SetLoaded(true);
3780 bool CFileItem::LoadDetails()
3784 if (HasVideoInfoTag())
3790 CLog::LogF(LOGERROR
, "Error opening video database");
3794 VIDEODATABASEDIRECTORY::CQueryParams params
;
3795 VIDEODATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(GetPath(), params
);
3798 auto tag
{std::make_unique
<CVideoInfoTag
>()};
3799 if (params
.GetMovieId() >= 0)
3800 ret
= db
.GetMovieInfo(GetPath(), *tag
, static_cast<int>(params
.GetMovieId()),
3801 static_cast<int>(params
.GetVideoVersionId()));
3802 else if (params
.GetMVideoId() >= 0)
3803 ret
= db
.GetMusicVideoInfo(GetPath(), *tag
, static_cast<int>(params
.GetMVideoId()));
3804 else if (params
.GetEpisodeId() >= 0)
3805 ret
= db
.GetEpisodeInfo(GetPath(), *tag
, static_cast<int>(params
.GetEpisodeId()));
3806 else if (params
.GetSetId() >= 0) // movie set
3807 ret
= db
.GetSetInfo(static_cast<int>(params
.GetSetId()), *tag
, this);
3808 else if (params
.GetTvShowId() >= 0)
3810 if (params
.GetSeason() >= 0)
3812 const int idSeason
= db
.GetSeasonId(static_cast<int>(params
.GetTvShowId()),
3813 static_cast<int>(params
.GetSeason()));
3815 ret
= db
.GetSeasonInfo(idSeason
, *tag
, this);
3818 ret
= db
.GetTvShowInfo(GetPath(), *tag
, static_cast<int>(params
.GetTvShowId()), this);
3823 const CFileItem loadedItem
{*tag
};
3824 UpdateInfo(loadedItem
);
3831 const std::shared_ptr
<CFileItem
> loadedItem
{
3832 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Utils
>().LoadItem(*this)};
3835 UpdateInfo(*loadedItem
);
3838 CLog::LogF(LOGERROR
, "Error filling PVR item details (path={})", GetPath());
3842 if (!IsPlayList() && IsVideo())
3844 if (HasVideoInfoTag())
3850 CLog::LogF(LOGERROR
, "Error opening video database");
3854 auto tag
{std::make_unique
<CVideoInfoTag
>()};
3855 if (db
.LoadVideoInfo(GetDynPath(), *tag
))
3857 const CFileItem loadedItem
{*tag
};
3858 UpdateInfo(loadedItem
);
3862 CLog::LogF(LOGERROR
, "Error filling item details (path={})", GetPath());
3866 if (IsPlayList() && IsType(".strm"))
3868 const std::unique_ptr
<PLAYLIST::CPlayList
> playlist(PLAYLIST::CPlayListFactory::Create(*this));
3871 if (playlist
->Load(GetPath()) && playlist
->size() == 1)
3873 const auto item
{(*playlist
)[0]};
3874 if (item
->IsVideo())
3879 CLog::LogF(LOGERROR
, "Error opening video database");
3884 if (db
.LoadVideoInfo(GetDynPath(), tag
))
3887 *GetVideoInfoTag() = tag
;
3891 else if (item
->IsAudio())
3893 if (item
->LoadMusicTag())
3901 CLog::LogF(LOGERROR
, "Error loading strm file details (path={})", GetPath());
3907 return LoadMusicTag();
3912 if (HasMusicInfoTag())
3918 CLog::LogF(LOGERROR
, "Error opening music database");
3922 MUSICDATABASEDIRECTORY::CQueryParams params
;
3923 MUSICDATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(GetPath(), params
);
3925 if (params
.GetSongId() >= 0)
3928 if (db
.GetSong(params
.GetSongId(), song
))
3930 GetMusicInfoTag()->SetSong(song
);
3934 else if (params
.GetAlbumId() >= 0)
3938 if (db
.GetAlbum(params
.GetAlbumId(), album
, false))
3940 GetMusicInfoTag()->SetAlbum(album
);
3944 else if (params
.GetArtistId() >= 0)
3948 if (db
.GetArtist(params
.GetArtistId(), artist
, false))
3950 GetMusicInfoTag()->SetArtist(artist
);
3957 //! @todo add support for other types on demand.
3958 CLog::LogF(LOGDEBUG
, "Unsupported item type (path={})", GetPath());
3962 void CFileItemList::Swap(unsigned int item1
, unsigned int item2
)
3964 if (item1
!= item2
&& item1
< m_items
.size() && item2
< m_items
.size())
3965 std::swap(m_items
[item1
], m_items
[item2
]);
3968 bool CFileItemList::UpdateItem(const CFileItem
*item
)
3973 std::unique_lock
<CCriticalSection
> lock(m_lock
);
3974 for (unsigned int i
= 0; i
< m_items
.size(); i
++)
3976 CFileItemPtr pItem
= m_items
[i
];
3977 if (pItem
->IsSamePath(item
))
3979 pItem
->UpdateInfo(*item
);
3986 void CFileItemList::AddSortMethod(SortBy sortBy
, int buttonLabel
, const LABEL_MASKS
&labelMasks
, SortAttribute sortAttributes
/* = SortAttributeNone */)
3988 AddSortMethod(sortBy
, sortAttributes
, buttonLabel
, labelMasks
);
3991 void CFileItemList::AddSortMethod(SortBy sortBy
, SortAttribute sortAttributes
, int buttonLabel
, const LABEL_MASKS
&labelMasks
)
3993 SortDescription sorting
;
3994 sorting
.sortBy
= sortBy
;
3995 sorting
.sortAttributes
= sortAttributes
;
3997 AddSortMethod(sorting
, buttonLabel
, labelMasks
);
4000 void CFileItemList::AddSortMethod(SortDescription sortDescription
, int buttonLabel
, const LABEL_MASKS
&labelMasks
)
4002 GUIViewSortDetails sort
;
4003 sort
.m_sortDescription
= sortDescription
;
4004 sort
.m_buttonLabel
= buttonLabel
;
4005 sort
.m_labelMasks
= labelMasks
;
4007 m_sortDetails
.push_back(sort
);
4010 void CFileItemList::SetReplaceListing(bool replace
)
4012 m_replaceListing
= replace
;
4015 void CFileItemList::ClearSortState()
4017 m_sortDescription
.sortBy
= SortByNone
;
4018 m_sortDescription
.sortOrder
= SortOrderNone
;
4019 m_sortDescription
.sortAttributes
= SortAttributeNone
;
4022 bool CFileItem::HasVideoInfoTag() const
4024 // Note: CPVRRecording is derived from CVideoInfoTag
4025 return m_pvrRecordingInfoTag
.get() != nullptr || m_videoInfoTag
!= nullptr;
4028 CVideoInfoTag
* CFileItem::GetVideoInfoTag()
4030 // Note: CPVRRecording is derived from CVideoInfoTag
4031 if (m_pvrRecordingInfoTag
)
4032 return m_pvrRecordingInfoTag
.get();
4033 else if (!m_videoInfoTag
)
4034 m_videoInfoTag
= new CVideoInfoTag
;
4036 return m_videoInfoTag
;
4039 const CVideoInfoTag
* CFileItem::GetVideoInfoTag() const
4041 // Note: CPVRRecording is derived from CVideoInfoTag
4042 return m_pvrRecordingInfoTag
? m_pvrRecordingInfoTag
.get() : m_videoInfoTag
;
4045 CPictureInfoTag
* CFileItem::GetPictureInfoTag()
4047 if (!m_pictureInfoTag
)
4048 m_pictureInfoTag
= new CPictureInfoTag
;
4050 return m_pictureInfoTag
;
4053 MUSIC_INFO::CMusicInfoTag
* CFileItem::GetMusicInfoTag()
4055 if (!m_musicInfoTag
)
4056 m_musicInfoTag
= new MUSIC_INFO::CMusicInfoTag
;
4058 return m_musicInfoTag
;
4061 CGameInfoTag
* CFileItem::GetGameInfoTag()
4064 m_gameInfoTag
= new CGameInfoTag
;
4066 return m_gameInfoTag
;
4069 bool CFileItem::HasPVRChannelInfoTag() const
4071 return m_pvrChannelGroupMemberInfoTag
&& m_pvrChannelGroupMemberInfoTag
->Channel() != nullptr;
4074 const std::shared_ptr
<PVR::CPVRChannel
> CFileItem::GetPVRChannelInfoTag() const
4076 return m_pvrChannelGroupMemberInfoTag
? m_pvrChannelGroupMemberInfoTag
->Channel()
4077 : std::shared_ptr
<CPVRChannel
>();
4080 std::string
CFileItem::FindTrailer() const
4082 std::string strFile2
;
4083 std::string strFile
= m_strPath
;
4086 std::string strPath
;
4087 URIUtils::GetParentPath(m_strPath
,strPath
);
4088 CStackDirectory dir
;
4089 std::string strPath2
;
4090 strPath2
= dir
.GetStackedTitlePath(strFile
);
4091 strFile
= URIUtils::AddFileToFolder(strPath
,URIUtils::GetFileName(strPath2
));
4092 CFileItem
item(dir
.GetFirstStackedFile(m_strPath
),false);
4093 std::string
strTBNFile(URIUtils::ReplaceExtension(item
.GetTBNFile(), "-trailer"));
4094 strFile2
= URIUtils::AddFileToFolder(strPath
,URIUtils::GetFileName(strTBNFile
));
4096 if (URIUtils::IsInRAR(strFile
) || URIUtils::IsInZIP(strFile
))
4098 std::string strPath
= URIUtils::GetDirectory(strFile
);
4099 std::string strParent
;
4100 URIUtils::GetParentPath(strPath
,strParent
);
4101 strFile
= URIUtils::AddFileToFolder(strParent
,URIUtils::GetFileName(m_strPath
));
4104 // no local trailer available for these
4105 if (IsInternetStream()
4106 || URIUtils::IsUPnP(strFile
)
4107 || URIUtils::IsBluray(strFile
)
4113 std::string strDir
= URIUtils::GetDirectory(strFile
);
4114 CFileItemList items
;
4115 CDirectory::GetDirectory(strDir
, items
, CServiceBroker::GetFileExtensionProvider().GetVideoExtensions(), DIR_FLAG_READ_CACHE
| DIR_FLAG_NO_FILE_INFO
| DIR_FLAG_NO_FILE_DIRS
);
4116 URIUtils::RemoveExtension(strFile
);
4117 strFile
+= "-trailer";
4118 std::string strFile3
= URIUtils::AddFileToFolder(strDir
, "movie-trailer");
4120 // Precompile our REs
4121 VECCREGEXP matchRegExps
;
4122 CRegExp
tmpRegExp(true, CRegExp::autoUtf8
);
4123 const std::vector
<std::string
>& strMatchRegExps
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_trailerMatchRegExps
;
4125 std::vector
<std::string
>::const_iterator strRegExp
= strMatchRegExps
.begin();
4126 while (strRegExp
!= strMatchRegExps
.end())
4128 if (tmpRegExp
.RegComp(*strRegExp
))
4130 matchRegExps
.push_back(tmpRegExp
);
4135 std::string strTrailer
;
4136 for (int i
= 0; i
< items
.Size(); i
++)
4138 std::string strCandidate
= items
[i
]->m_strPath
;
4139 URIUtils::RemoveExtension(strCandidate
);
4140 if (StringUtils::EqualsNoCase(strCandidate
, strFile
) ||
4141 StringUtils::EqualsNoCase(strCandidate
, strFile2
) ||
4142 StringUtils::EqualsNoCase(strCandidate
, strFile3
))
4144 strTrailer
= items
[i
]->m_strPath
;
4149 VECCREGEXP::iterator expr
= matchRegExps
.begin();
4151 while (expr
!= matchRegExps
.end())
4153 if (expr
->RegFind(strCandidate
) != -1)
4155 strTrailer
= items
[i
]->m_strPath
;
4167 VideoDbContentType
CFileItem::GetVideoContentType() const
4169 VideoDbContentType type
= VideoDbContentType::MOVIES
;
4170 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type
== MediaTypeTvShow
)
4171 type
= VideoDbContentType::TVSHOWS
;
4172 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type
== MediaTypeEpisode
)
4173 return VideoDbContentType::EPISODES
;
4174 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type
== MediaTypeMusicVideo
)
4175 return VideoDbContentType::MUSICVIDEOS
;
4176 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type
== MediaTypeAlbum
)
4177 return VideoDbContentType::MUSICALBUMS
;
4179 CVideoDatabaseDirectory dir
;
4180 VIDEODATABASEDIRECTORY::CQueryParams params
;
4181 dir
.GetQueryParams(m_strPath
, params
);
4182 if (params
.GetSetId() != -1 && params
.GetMovieId() == -1) // movie set
4183 return VideoDbContentType::MOVIE_SETS
;
4188 CFileItem
CFileItem::GetItemToPlay() const
4190 if (HasEPGInfoTag())
4192 const std::shared_ptr
<CPVRChannelGroupMember
> groupMember
=
4193 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Channels
>().GetChannelGroupMember(*this);
4195 return CFileItem(groupMember
);
4200 CBookmark
CFileItem::GetResumePoint() const
4202 if (HasVideoInfoTag())
4203 return GetVideoInfoTag()->GetResumePoint();
4207 bool CFileItem::IsResumePointSet() const
4209 return GetResumePoint().IsSet();
4212 double CFileItem::GetCurrentResumeTime() const
4214 return lrint(GetResumePoint().timeInSeconds
);
4217 bool CFileItem::GetCurrentResumeTimeAndPartNumber(int64_t& startOffset
, int& partNumber
) const
4219 CBookmark
resumePoint(GetResumePoint());
4220 if (resumePoint
.IsSet())
4222 startOffset
= llrint(resumePoint
.timeInSeconds
);
4223 partNumber
= resumePoint
.partNumber
;
4229 bool CFileItem::IsResumable() const
4233 int64_t watched
= 0;
4234 int64_t inprogress
= 0;
4236 if (HasProperty("inprogressepisodes"))
4239 watched
= GetProperty("watchedepisodes").asInteger();
4240 inprogress
= GetProperty("inprogressepisodes").asInteger();
4241 total
= GetProperty("totalepisodes").asInteger();
4243 else if (HasProperty("inprogress"))
4246 watched
= GetProperty("watched").asInteger();
4247 inprogress
= GetProperty("inprogress").asInteger();
4248 total
= GetProperty("total").asInteger();
4251 return ((total
!= watched
) && (inprogress
> 0 || watched
!= 0));
4255 return HasVideoInfoTag() && GetVideoInfoTag()->GetResumePoint().IsPartWay();
4259 bool CFileItem::HasVideoVersions() const
4261 if (HasVideoInfoTag())
4263 return GetVideoInfoTag()->HasVideoVersions();
4268 bool CFileItem::HasVideoExtras() const
4270 if (HasVideoInfoTag())
4272 return GetVideoInfoTag()->HasVideoExtras();