[XAudio2] avoid leak + fix voice creation for closest match
[xbmc.git] / xbmc / FileItem.cpp
blob9efa598f827b8221defc588938673c622813c21f
1 /*
2 * Copyright (C) 2005-2020 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "FileItem.h"
11 #include "CueDocument.h"
12 #include "FileItemList.h"
13 #include "ServiceBroker.h"
14 #include "URL.h"
15 #include "Util.h"
16 #include "events/IEvent.h"
17 #include "filesystem/CurlFile.h"
18 #include "filesystem/Directory.h"
19 #include "filesystem/File.h"
20 #include "filesystem/MultiPathDirectory.h"
21 #include "filesystem/MusicDatabaseDirectory/QueryParams.h"
22 #include "filesystem/StackDirectory.h"
23 #include "filesystem/VideoDatabaseDirectory.h"
24 #include "filesystem/VideoDatabaseDirectory/QueryParams.h"
25 #include "games/GameUtils.h"
26 #include "games/tags/GameInfoTag.h"
27 #include "guilib/LocalizeStrings.h"
28 #include "media/MediaLockState.h"
29 #include "music/Album.h"
30 #include "music/Artist.h"
31 #include "music/MusicDatabase.h"
32 #include "music/MusicFileItemClassify.h"
33 #include "music/tags/MusicInfoTag.h"
34 #include "music/tags/MusicInfoTagLoaderFactory.h"
35 #include "network/NetworkFileItemClassify.h"
36 #include "pictures/PictureInfoTag.h"
37 #include "playlists/PlayList.h"
38 #include "playlists/PlayListFactory.h"
39 #include "playlists/PlayListFileItemClassify.h"
40 #include "pvr/PVRManager.h"
41 #include "pvr/channels/PVRChannel.h"
42 #include "pvr/channels/PVRChannelGroupMember.h"
43 #include "pvr/epg/EpgInfoTag.h"
44 #include "pvr/epg/EpgSearchFilter.h"
45 #include "pvr/guilib/PVRGUIActionsChannels.h"
46 #include "pvr/guilib/PVRGUIActionsEPG.h"
47 #include "pvr/guilib/PVRGUIActionsUtils.h"
48 #include "pvr/providers/PVRProvider.h"
49 #include "pvr/recordings/PVRRecording.h"
50 #include "pvr/timers/PVRTimerInfoTag.h"
51 #include "settings/AdvancedSettings.h"
52 #include "settings/SettingUtils.h"
53 #include "settings/Settings.h"
54 #include "settings/SettingsComponent.h"
55 #include "settings/lib/Setting.h"
56 #include "utils/Archive.h"
57 #include "utils/ArtUtils.h"
58 #include "utils/FileExtensionProvider.h"
59 #include "utils/Mime.h"
60 #include "utils/RegExp.h"
61 #include "utils/StringUtils.h"
62 #include "utils/URIUtils.h"
63 #include "utils/Variant.h"
64 #include "utils/log.h"
65 #include "video/Bookmark.h"
66 #include "video/VideoDatabase.h"
67 #include "video/VideoFileItemClassify.h"
68 #include "video/VideoInfoTag.h"
69 #include "video/VideoUtils.h"
71 #include <cstdlib>
72 #include <memory>
74 using namespace KODI;
75 using namespace XFILE;
76 using namespace PLAYLIST;
77 using namespace MUSIC_INFO;
78 using namespace PVR;
79 using namespace GAME;
81 CFileItem::CFileItem(const CSong& song)
83 Initialize();
84 SetFromSong(song);
87 CFileItem::CFileItem(const CSong& song, const CMusicInfoTag& music)
89 Initialize();
90 SetFromSong(song);
91 *GetMusicInfoTag() = music;
94 CFileItem::CFileItem(const CURL &url, const CAlbum& album)
96 Initialize();
98 m_strPath = url.Get();
99 URIUtils::AddSlashAtEnd(m_strPath);
100 SetFromAlbum(album);
103 CFileItem::CFileItem(const std::string &path, const CAlbum& album)
105 Initialize();
107 m_strPath = path;
108 URIUtils::AddSlashAtEnd(m_strPath);
109 SetFromAlbum(album);
112 CFileItem::CFileItem(const CMusicInfoTag& music)
114 Initialize();
115 SetLabel(music.GetTitle());
116 m_strPath = music.GetURL();
117 m_bIsFolder = URIUtils::HasSlashAtEnd(m_strPath);
118 *GetMusicInfoTag() = music;
119 ART::FillInDefaultIcon(*this);
120 FillInMimeType(false);
123 CFileItem::CFileItem(const CVideoInfoTag& movie)
125 Initialize();
126 SetFromVideoInfoTag(movie);
129 void CFileItem::FillMusicInfoTag(const std::shared_ptr<const CPVREpgInfoTag>& tag)
131 CMusicInfoTag* musictag = GetMusicInfoTag(); // create (!) the music tag.
133 musictag->SetTitle(CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().GetTitleForEpgTag(tag));
135 if (tag)
137 musictag->SetGenre(tag->Genre());
138 musictag->SetDuration(tag->GetDuration());
139 musictag->SetURL(tag->Path());
142 musictag->SetLoaded(true);
145 CFileItem::CFileItem(const std::shared_ptr<CPVREpgInfoTag>& tag)
147 Initialize();
149 m_bIsFolder = false;
150 m_epgInfoTag = tag;
151 m_strPath = tag->Path();
152 m_bCanQueue = false;
153 SetLabel(CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().GetTitleForEpgTag(tag));
154 m_dateTime = tag->StartAsLocalTime();
156 if (!tag->IconPath().empty())
158 SetArt("icon", tag->IconPath());
160 else
162 const std::string iconPath = tag->ChannelIconPath();
163 if (!iconPath.empty())
164 SetArt("icon", iconPath);
165 else if (tag->IsRadio())
166 SetArt("icon", "DefaultMusicSongs.png");
167 else
168 SetArt("icon", "DefaultTVShows.png");
171 // Speedup FillInDefaultIcon()
172 SetProperty("icon_never_overlay", true);
174 if (tag->IsRadio() && !HasMusicInfoTag())
175 FillMusicInfoTag(tag);
177 FillInMimeType(false);
180 CFileItem::CFileItem(const std::shared_ptr<PVR::CPVREpgSearchFilter>& filter)
182 Initialize();
184 m_bIsFolder = true;
185 m_epgSearchFilter = filter;
186 m_strPath = filter->GetPath();
187 m_bCanQueue = false;
188 SetLabel(filter->GetTitle());
190 const CDateTime lastExec = filter->GetLastExecutedDateTime();
191 if (lastExec.IsValid())
192 m_dateTime.SetFromUTCDateTime(lastExec);
194 const std::string iconPath = filter->GetIconPath();
195 if (!iconPath.empty())
196 SetArt("icon", iconPath);
197 else
198 SetArt("icon", "DefaultPVRSearch.png");
200 // Speedup FillInDefaultIcon()
201 SetProperty("icon_never_overlay", true);
203 FillInMimeType(false);
206 CFileItem::CFileItem(const std::shared_ptr<CPVRChannelGroupMember>& channelGroupMember)
208 Initialize();
210 const std::shared_ptr<const CPVRChannel> channel = channelGroupMember->Channel();
212 m_pvrChannelGroupMemberInfoTag = channelGroupMember;
214 m_strPath = channelGroupMember->Path();
215 m_bIsFolder = false;
216 m_bCanQueue = false;
217 SetLabel(channel->ChannelName());
219 if (!channel->IconPath().empty())
220 SetArt("icon", channel->IconPath());
221 else if (channel->IsRadio())
222 SetArt("icon", "DefaultMusicSongs.png");
223 else
224 SetArt("icon", "DefaultTVShows.png");
226 SetProperty("channelid", channel->ChannelID());
227 SetProperty("path", channelGroupMember->Path());
228 SetArt("thumb", channel->IconPath());
230 // Speedup FillInDefaultIcon()
231 SetProperty("icon_never_overlay", true);
233 if (channel->IsRadio() && !HasMusicInfoTag())
235 const std::shared_ptr<const CPVREpgInfoTag> epgNow = channel->GetEPGNow();
236 FillMusicInfoTag(epgNow);
238 FillInMimeType(false);
241 CFileItem::CFileItem(const std::shared_ptr<CPVRRecording>& record)
243 Initialize();
245 m_bIsFolder = false;
246 m_pvrRecordingInfoTag = record;
247 m_strPath = record->m_strFileNameAndPath;
248 SetLabel(record->m_strTitle);
249 m_dateTime = record->RecordingTimeAsLocalTime();
250 m_dwSize = record->GetSizeInBytes();
251 m_bCanQueue = true;
253 // Set art
254 if (!record->IconPath().empty())
255 SetArt("icon", record->IconPath());
256 else
258 const std::shared_ptr<const CPVRChannel> channel = record->Channel();
259 if (channel && !channel->IconPath().empty())
260 SetArt("icon", channel->IconPath());
261 else if (record->IsRadio())
262 SetArt("icon", "DefaultMusicSongs.png");
263 else
264 SetArt("icon", "DefaultTVShows.png");
267 if (!record->ThumbnailPath().empty())
268 SetArt("thumb", record->ThumbnailPath());
270 if (!record->FanartPath().empty())
271 SetArt("fanart", record->FanartPath());
273 // Speedup FillInDefaultIcon()
274 SetProperty("icon_never_overlay", true);
276 FillInMimeType(false);
279 CFileItem::CFileItem(const std::shared_ptr<CPVRTimerInfoTag>& timer)
281 Initialize();
283 m_bIsFolder = timer->IsTimerRule();
284 m_pvrTimerInfoTag = timer;
285 m_strPath = timer->Path();
286 SetLabel(timer->Title());
287 m_dateTime = timer->StartAsLocalTime();
288 m_bCanQueue = false;
290 if (!timer->ChannelIcon().empty())
291 SetArt("icon", timer->ChannelIcon());
292 else if (timer->IsRadio())
293 SetArt("icon", "DefaultMusicSongs.png");
294 else
295 SetArt("icon", "DefaultTVShows.png");
297 // Speedup FillInDefaultIcon()
298 SetProperty("icon_never_overlay", true);
300 FillInMimeType(false);
303 CFileItem::CFileItem(const std::string& path, const std::shared_ptr<CPVRProvider>& provider)
305 Initialize();
307 m_strPath = path;
308 m_bIsFolder = true;
309 m_pvrProviderInfoTag = provider;
310 SetLabel(provider->GetName());
311 m_bCanQueue = false;
313 // Set art
314 if (!provider->GetIconPath().empty())
315 SetArt("icon", provider->GetIconPath());
316 else
317 SetArt("icon", "DefaultPVRProvider.png");
319 if (!provider->GetThumbPath().empty())
320 SetArt("thumb", provider->GetThumbPath());
322 // Speedup FillInDefaultIcon()
323 SetProperty("icon_never_overlay", true);
325 FillInMimeType(false);
328 CFileItem::CFileItem(const CArtist& artist)
330 Initialize();
331 SetLabel(artist.strArtist);
332 m_strPath = artist.strArtist;
333 m_bIsFolder = true;
334 URIUtils::AddSlashAtEnd(m_strPath);
335 GetMusicInfoTag()->SetArtist(artist);
336 FillInMimeType(false);
339 CFileItem::CFileItem(const CGenre& genre)
341 Initialize();
342 SetLabel(genre.strGenre);
343 m_strPath = genre.strGenre;
344 m_bIsFolder = true;
345 URIUtils::AddSlashAtEnd(m_strPath);
346 GetMusicInfoTag()->SetGenre(genre.strGenre);
347 FillInMimeType(false);
350 CFileItem::CFileItem(const CFileItem& item)
351 : CGUIListItem(item),
352 m_musicInfoTag(NULL),
353 m_videoInfoTag(NULL),
354 m_pictureInfoTag(NULL),
355 m_gameInfoTag(NULL)
357 *this = item;
360 CFileItem::CFileItem(const CGUIListItem& item)
362 Initialize();
363 // not particularly pretty, but it gets around the issue of Initialize() defaulting
364 // parameters in the CGUIListItem base class.
365 *static_cast<CGUIListItem*>(this) = item;
367 FillInMimeType(false);
370 CFileItem::CFileItem(void)
372 Initialize();
375 CFileItem::CFileItem(const std::string& strLabel)
377 Initialize();
378 SetLabel(strLabel);
381 CFileItem::CFileItem(const char* strLabel)
383 Initialize();
384 SetLabel(std::string(strLabel));
387 CFileItem::CFileItem(const CURL& path, bool bIsFolder)
389 Initialize();
390 m_strPath = path.Get();
391 m_bIsFolder = bIsFolder;
392 if (m_bIsFolder && !m_strPath.empty() && !IsFileFolder())
393 URIUtils::AddSlashAtEnd(m_strPath);
394 FillInMimeType(false);
397 CFileItem::CFileItem(const std::string& strPath, bool bIsFolder)
399 Initialize();
400 m_strPath = strPath;
401 m_bIsFolder = bIsFolder;
402 if (m_bIsFolder && !m_strPath.empty() && !IsFileFolder())
403 URIUtils::AddSlashAtEnd(m_strPath);
404 FillInMimeType(false);
407 CFileItem::CFileItem(const CMediaSource& share)
409 Initialize();
410 m_bIsFolder = true;
411 m_bIsShareOrDrive = true;
412 m_strPath = share.strPath;
413 if (!IsRSS()) // no slash at end for rss feeds
414 URIUtils::AddSlashAtEnd(m_strPath);
415 std::string label = share.strName;
416 if (!share.strStatus.empty())
417 label = StringUtils::Format("{} ({})", share.strName, share.strStatus);
418 SetLabel(label);
419 m_iLockMode = share.m_iLockMode;
420 m_strLockCode = share.m_strLockCode;
421 m_iHasLock = share.m_iHasLock;
422 m_iBadPwdCount = share.m_iBadPwdCount;
423 m_iDriveType = share.m_iDriveType;
424 SetArt("thumb", share.m_strThumbnailImage);
425 SetLabelPreformatted(true);
426 if (IsDVD())
427 GetVideoInfoTag()->m_strFileNameAndPath = share.strDiskUniqueId; // share.strDiskUniqueId contains disc unique id
428 FillInMimeType(false);
431 CFileItem::CFileItem(std::shared_ptr<const ADDON::IAddon> addonInfo) : m_addonInfo(std::move(addonInfo))
433 Initialize();
436 CFileItem::CFileItem(const EventPtr& eventLogEntry)
438 Initialize();
440 m_eventLogEntry = eventLogEntry;
441 SetLabel(eventLogEntry->GetLabel());
442 m_dateTime = eventLogEntry->GetDateTime();
443 if (!eventLogEntry->GetIcon().empty())
444 SetArt("icon", eventLogEntry->GetIcon());
447 CFileItem::~CFileItem(void)
449 delete m_musicInfoTag;
450 delete m_videoInfoTag;
451 delete m_pictureInfoTag;
452 delete m_gameInfoTag;
454 m_musicInfoTag = NULL;
455 m_videoInfoTag = NULL;
456 m_pictureInfoTag = NULL;
457 m_gameInfoTag = NULL;
460 CFileItem& CFileItem::operator=(const CFileItem& item)
462 if (this == &item)
463 return *this;
465 CGUIListItem::operator=(item);
466 m_bLabelPreformatted=item.m_bLabelPreformatted;
467 FreeMemory();
468 m_strPath = item.m_strPath;
469 m_strDynPath = item.m_strDynPath;
470 m_bIsParentFolder = item.m_bIsParentFolder;
471 m_iDriveType = item.m_iDriveType;
472 m_bIsShareOrDrive = item.m_bIsShareOrDrive;
473 m_dateTime = item.m_dateTime;
474 m_dwSize = item.m_dwSize;
476 if (item.m_musicInfoTag)
478 if (m_musicInfoTag)
479 *m_musicInfoTag = *item.m_musicInfoTag;
480 else
481 m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag(*item.m_musicInfoTag);
483 else
485 delete m_musicInfoTag;
486 m_musicInfoTag = NULL;
489 if (item.m_videoInfoTag)
491 if (m_videoInfoTag)
492 *m_videoInfoTag = *item.m_videoInfoTag;
493 else
494 m_videoInfoTag = new CVideoInfoTag(*item.m_videoInfoTag);
496 else
498 delete m_videoInfoTag;
499 m_videoInfoTag = NULL;
502 if (item.m_pictureInfoTag)
504 if (m_pictureInfoTag)
505 *m_pictureInfoTag = *item.m_pictureInfoTag;
506 else
507 m_pictureInfoTag = new CPictureInfoTag(*item.m_pictureInfoTag);
509 else
511 delete m_pictureInfoTag;
512 m_pictureInfoTag = NULL;
515 if (item.m_gameInfoTag)
517 if (m_gameInfoTag)
518 *m_gameInfoTag = *item.m_gameInfoTag;
519 else
520 m_gameInfoTag = new CGameInfoTag(*item.m_gameInfoTag);
522 else
524 delete m_gameInfoTag;
525 m_gameInfoTag = NULL;
528 m_epgInfoTag = item.m_epgInfoTag;
529 m_epgSearchFilter = item.m_epgSearchFilter;
530 m_pvrChannelGroupMemberInfoTag = item.m_pvrChannelGroupMemberInfoTag;
531 m_pvrRecordingInfoTag = item.m_pvrRecordingInfoTag;
532 m_pvrTimerInfoTag = item.m_pvrTimerInfoTag;
533 m_pvrProviderInfoTag = item.m_pvrProviderInfoTag;
534 m_addonInfo = item.m_addonInfo;
535 m_eventLogEntry = item.m_eventLogEntry;
537 m_lStartOffset = item.m_lStartOffset;
538 m_lStartPartNumber = item.m_lStartPartNumber;
539 m_lEndOffset = item.m_lEndOffset;
540 m_strDVDLabel = item.m_strDVDLabel;
541 m_strTitle = item.m_strTitle;
542 m_iprogramCount = item.m_iprogramCount;
543 m_idepth = item.m_idepth;
544 m_iLockMode = item.m_iLockMode;
545 m_strLockCode = item.m_strLockCode;
546 m_iHasLock = item.m_iHasLock;
547 m_iBadPwdCount = item.m_iBadPwdCount;
548 m_bCanQueue=item.m_bCanQueue;
549 m_mimetype = item.m_mimetype;
550 m_extrainfo = item.m_extrainfo;
551 m_specialSort = item.m_specialSort;
552 m_bIsAlbum = item.m_bIsAlbum;
553 m_doContentLookup = item.m_doContentLookup;
554 return *this;
557 void CFileItem::Initialize()
559 m_musicInfoTag = NULL;
560 m_videoInfoTag = NULL;
561 m_pictureInfoTag = NULL;
562 m_gameInfoTag = NULL;
563 m_bLabelPreformatted = false;
564 m_bIsAlbum = false;
565 m_dwSize = 0;
566 m_bIsParentFolder = false;
567 m_bIsShareOrDrive = false;
568 m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
569 m_lStartOffset = 0;
570 m_lStartPartNumber = 1;
571 m_lEndOffset = 0;
572 m_iprogramCount = 0;
573 m_idepth = 1;
574 m_iLockMode = LOCK_MODE_EVERYONE;
575 m_iBadPwdCount = 0;
576 m_iHasLock = LOCK_STATE_NO_LOCK;
577 m_bCanQueue = true;
578 m_specialSort = SortSpecialNone;
579 m_doContentLookup = true;
582 void CFileItem::Reset()
584 // CGUIListItem members...
585 m_strLabel2.clear();
586 SetLabel("");
587 FreeIcons();
588 m_overlayIcon = ICON_OVERLAY_NONE;
589 m_bSelected = false;
590 m_bIsFolder = false;
592 m_strDVDLabel.clear();
593 m_strTitle.clear();
594 m_strPath.clear();
595 m_strDynPath.clear();
596 m_dateTime.Reset();
597 m_strLockCode.clear();
598 m_mimetype.clear();
599 delete m_musicInfoTag;
600 m_musicInfoTag=NULL;
601 delete m_videoInfoTag;
602 m_videoInfoTag=NULL;
603 m_epgInfoTag.reset();
604 m_epgSearchFilter.reset();
605 m_pvrChannelGroupMemberInfoTag.reset();
606 m_pvrRecordingInfoTag.reset();
607 m_pvrTimerInfoTag.reset();
608 m_pvrProviderInfoTag.reset();
609 delete m_pictureInfoTag;
610 m_pictureInfoTag=NULL;
611 delete m_gameInfoTag;
612 m_gameInfoTag = NULL;
613 m_extrainfo.clear();
614 ClearProperties();
615 m_eventLogEntry.reset();
617 Initialize();
618 SetInvalid();
621 // do not archive dynamic path
622 void CFileItem::Archive(CArchive& ar)
624 CGUIListItem::Archive(ar);
626 if (ar.IsStoring())
628 ar << m_bIsParentFolder;
629 ar << m_bLabelPreformatted;
630 ar << m_strPath;
631 ar << m_bIsShareOrDrive;
632 ar << m_iDriveType;
633 ar << m_dateTime;
634 ar << m_dwSize;
635 ar << m_strDVDLabel;
636 ar << m_strTitle;
637 ar << m_iprogramCount;
638 ar << m_idepth;
639 ar << m_lStartOffset;
640 ar << m_lStartPartNumber;
641 ar << m_lEndOffset;
642 ar << m_iLockMode;
643 ar << m_strLockCode;
644 ar << m_iBadPwdCount;
646 ar << m_bCanQueue;
647 ar << m_mimetype;
648 ar << m_extrainfo;
649 ar << m_specialSort;
650 ar << m_doContentLookup;
652 if (m_musicInfoTag)
654 ar << 1;
655 ar << *m_musicInfoTag;
657 else
658 ar << 0;
659 if (m_videoInfoTag)
661 ar << 1;
662 ar << *m_videoInfoTag;
664 else
665 ar << 0;
666 if (m_pictureInfoTag)
668 ar << 1;
669 ar << *m_pictureInfoTag;
671 else
672 ar << 0;
673 if (m_gameInfoTag)
675 ar << 1;
676 ar << *m_gameInfoTag;
678 else
679 ar << 0;
681 else
683 ar >> m_bIsParentFolder;
684 ar >> m_bLabelPreformatted;
685 ar >> m_strPath;
686 ar >> m_bIsShareOrDrive;
687 ar >> m_iDriveType;
688 ar >> m_dateTime;
689 ar >> m_dwSize;
690 ar >> m_strDVDLabel;
691 ar >> m_strTitle;
692 ar >> m_iprogramCount;
693 ar >> m_idepth;
694 ar >> m_lStartOffset;
695 ar >> m_lStartPartNumber;
696 ar >> m_lEndOffset;
697 int temp;
698 ar >> temp;
699 m_iLockMode = (LockType)temp;
700 ar >> m_strLockCode;
701 ar >> m_iBadPwdCount;
703 ar >> m_bCanQueue;
704 ar >> m_mimetype;
705 ar >> m_extrainfo;
706 ar >> temp;
707 m_specialSort = (SortSpecial)temp;
708 ar >> m_doContentLookup;
710 int iType;
711 ar >> iType;
712 if (iType == 1)
713 ar >> *GetMusicInfoTag();
714 ar >> iType;
715 if (iType == 1)
716 ar >> *GetVideoInfoTag();
717 ar >> iType;
718 if (iType == 1)
719 ar >> *GetPictureInfoTag();
720 ar >> iType;
721 if (iType == 1)
722 ar >> *GetGameInfoTag();
724 SetInvalid();
728 void CFileItem::Serialize(CVariant& value) const
730 //CGUIListItem::Serialize(value["CGUIListItem"]);
732 value["strPath"] = m_strPath;
733 value["dateTime"] = (m_dateTime.IsValid()) ? m_dateTime.GetAsRFC1123DateTime() : "";
734 value["lastmodified"] = m_dateTime.IsValid() ? m_dateTime.GetAsDBDateTime() : "";
735 value["size"] = m_dwSize;
736 value["DVDLabel"] = m_strDVDLabel;
737 value["title"] = m_strTitle;
738 value["mimetype"] = m_mimetype;
739 value["extrainfo"] = m_extrainfo;
741 if (m_musicInfoTag)
742 (*m_musicInfoTag).Serialize(value["musicInfoTag"]);
744 if (m_videoInfoTag)
745 (*m_videoInfoTag).Serialize(value["videoInfoTag"]);
747 if (m_pictureInfoTag)
748 (*m_pictureInfoTag).Serialize(value["pictureInfoTag"]);
750 if (m_gameInfoTag)
751 (*m_gameInfoTag).Serialize(value["gameInfoTag"]);
753 if (!m_mapProperties.empty())
755 auto& customProperties = value["customproperties"];
756 for (const auto& prop : m_mapProperties)
757 customProperties[prop.first] = prop.second;
761 void CFileItem::ToSortable(SortItem &sortable, Field field) const
763 switch (field)
765 case FieldPath:
766 sortable[FieldPath] = m_strPath;
767 break;
768 case FieldDate:
769 sortable[FieldDate] = (m_dateTime.IsValid()) ? m_dateTime.GetAsDBDateTime() : "";
770 break;
771 case FieldSize:
772 sortable[FieldSize] = m_dwSize;
773 break;
774 case FieldDriveType:
775 sortable[FieldDriveType] = m_iDriveType;
776 break;
777 case FieldStartOffset:
778 sortable[FieldStartOffset] = m_lStartOffset;
779 break;
780 case FieldEndOffset:
781 sortable[FieldEndOffset] = m_lEndOffset;
782 break;
783 case FieldProgramCount:
784 sortable[FieldProgramCount] = m_iprogramCount;
785 break;
786 case FieldBitrate:
787 sortable[FieldBitrate] = m_dwSize;
788 break;
789 case FieldTitle:
790 sortable[FieldTitle] = m_strTitle;
791 break;
793 // If there's ever a need to convert more properties from CGUIListItem it might be
794 // worth to make CGUIListItem implement ISortable as well and call it from here
796 default:
797 break;
800 if (HasMusicInfoTag())
801 GetMusicInfoTag()->ToSortable(sortable, field);
803 if (HasVideoInfoTag())
804 GetVideoInfoTag()->ToSortable(sortable, field);
806 if (HasPictureInfoTag())
807 GetPictureInfoTag()->ToSortable(sortable, field);
809 if (HasPVRChannelInfoTag())
810 GetPVRChannelInfoTag()->ToSortable(sortable, field);
812 if (HasPVRChannelGroupMemberInfoTag())
813 GetPVRChannelGroupMemberInfoTag()->ToSortable(sortable, field);
815 if (HasPVRProviderInfoTag())
816 GetPVRProviderInfoTag()->ToSortable(sortable, field);
818 if (HasAddonInfo())
820 switch (field)
822 case FieldInstallDate:
823 sortable[FieldInstallDate] = GetAddonInfo()->InstallDate().GetAsDBDateTime();
824 break;
825 case FieldLastUpdated:
826 sortable[FieldLastUpdated] = GetAddonInfo()->LastUpdated().GetAsDBDateTime();
827 break;
828 case FieldLastUsed:
829 sortable[FieldLastUsed] = GetAddonInfo()->LastUsed().GetAsDBDateTime();
830 break;
831 default:
832 break;
836 if (HasGameInfoTag())
837 GetGameInfoTag()->ToSortable(sortable, field);
839 if (m_eventLogEntry)
840 m_eventLogEntry->ToSortable(sortable, field);
842 if (IsFavourite())
844 if (field == FieldUserPreference)
845 sortable[FieldUserPreference] = GetProperty("favourite.index").asString();
849 void CFileItem::ToSortable(SortItem &sortable, const Fields &fields) const
851 Fields::const_iterator it;
852 for (it = fields.begin(); it != fields.end(); ++it)
853 ToSortable(sortable, *it);
855 /* FieldLabel is used as a fallback by all sorters and therefore has to be present as well */
856 sortable[FieldLabel] = GetLabel();
857 /* FieldSortSpecial and FieldFolder are required in conjunction with all other sorters as well */
858 sortable[FieldSortSpecial] = m_specialSort;
859 sortable[FieldFolder] = m_bIsFolder;
862 bool CFileItem::Exists(bool bUseCache /* = true */) const
864 if (m_strPath.empty() || IsPath("add") || NETWORK::IsInternetStream(*this) || IsParentFolder() ||
865 IsVirtualDirectoryRoot() || IsPlugin() || IsPVR())
866 return true;
868 if (VIDEO::IsVideoDb(*this) && HasVideoInfoTag())
870 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
871 return dbItem.Exists();
874 std::string strPath = m_strPath;
876 if (URIUtils::IsMultiPath(strPath))
877 strPath = CMultiPathDirectory::GetFirstPath(strPath);
879 if (URIUtils::IsStack(strPath))
880 strPath = CStackDirectory::GetFirstStackedFile(strPath);
882 if (m_bIsFolder)
883 return CDirectory::Exists(strPath, bUseCache);
884 else
885 return CFile::Exists(strPath, bUseCache);
887 return false;
890 bool CFileItem::IsEPG() const
892 return HasEPGInfoTag();
895 bool CFileItem::IsPVRChannel() const
897 return HasPVRChannelInfoTag();
900 bool CFileItem::IsPVRChannelGroup() const
902 return URIUtils::IsPVRChannelGroup(m_strPath);
905 bool CFileItem::IsPVRRecording() const
907 return HasPVRRecordingInfoTag();
910 bool CFileItem::IsUsablePVRRecording() const
912 return (m_pvrRecordingInfoTag && !m_pvrRecordingInfoTag->IsDeleted());
915 bool CFileItem::IsDeletedPVRRecording() const
917 return (m_pvrRecordingInfoTag && m_pvrRecordingInfoTag->IsDeleted());
920 bool CFileItem::IsInProgressPVRRecording() const
922 return (m_pvrRecordingInfoTag && m_pvrRecordingInfoTag->IsInProgress());
925 bool CFileItem::IsPVRTimer() const
927 return HasPVRTimerInfoTag();
930 bool CFileItem::IsPVRProvider() const
932 return HasPVRProviderInfoTag();
935 bool CFileItem::IsDeleted() const
937 if (HasPVRRecordingInfoTag())
938 return GetPVRRecordingInfoTag()->IsDeleted();
940 return false;
943 bool CFileItem::IsGame() const
945 if (HasGameInfoTag())
946 return true;
948 if (HasVideoInfoTag())
949 return false;
951 if (HasMusicInfoTag())
952 return false;
954 if (HasPictureInfoTag())
955 return false;
957 if (IsPVR())
958 return false;
960 if (HasAddonInfo())
961 return CGameUtils::IsStandaloneGame(std::const_pointer_cast<ADDON::IAddon>(GetAddonInfo()));
963 return CGameUtils::HasGameExtension(m_strPath);
966 bool CFileItem::IsPicture() const
968 if (StringUtils::StartsWithNoCase(m_mimetype, "image/"))
969 return true;
971 if (HasPictureInfoTag())
972 return true;
974 if (HasGameInfoTag())
975 return false;
977 if (HasMusicInfoTag())
978 return false;
980 if (HasVideoInfoTag())
981 return false;
983 if (HasPVRTimerInfoTag() || HasPVRChannelInfoTag() || HasPVRChannelGroupMemberInfoTag() ||
984 HasPVRRecordingInfoTag() || HasEPGInfoTag() || HasEPGSearchFilter() ||
985 HasPVRProviderInfoTag())
986 return false;
988 if (!m_strPath.empty())
989 return CUtil::IsPicture(m_strPath);
991 return false;
994 bool CFileItem::IsFileFolder(EFileFolderType types) const
996 EFileFolderType always_type = EFILEFOLDER_TYPE_ALWAYS;
998 /* internet streams are not directly expanded */
999 if (NETWORK::IsInternetStream(*this))
1000 always_type = EFILEFOLDER_TYPE_ONCLICK;
1002 // strm files are not browsable
1003 if (IsType(".strm") && (types & EFILEFOLDER_TYPE_ONBROWSE))
1004 return false;
1006 if (types & always_type)
1008 if (PLAYLIST::IsSmartPlayList(*this) ||
1009 (PLAYLIST::IsPlayList(*this) &&
1010 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_playlistAsFolders) ||
1011 IsAPK() || IsZIP() || IsRAR() || IsRSS() || MUSIC::IsAudioBook(*this) ||
1012 IsType(".ogg|.oga|.xbt")
1013 #if defined(TARGET_ANDROID)
1014 || IsType(".apk")
1015 #endif
1017 return true;
1020 if (CServiceBroker::IsAddonInterfaceUp() &&
1021 IsType(CServiceBroker::GetFileExtensionProvider().GetFileFolderExtensions().c_str()) &&
1022 CServiceBroker::GetFileExtensionProvider().CanOperateExtension(m_strPath))
1023 return true;
1025 if(types & EFILEFOLDER_TYPE_ONBROWSE)
1027 if ((PLAYLIST::IsPlayList(*this) &&
1028 !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_playlistAsFolders) ||
1029 IsDiscImage())
1030 return true;
1033 return false;
1036 bool CFileItem::IsLibraryFolder() const
1038 if (HasProperty("library.filter") && GetProperty("library.filter").asBoolean())
1039 return true;
1041 return URIUtils::IsLibraryFolder(m_strPath);
1044 bool CFileItem::IsPythonScript() const
1046 return URIUtils::HasExtension(m_strPath, ".py");
1049 bool CFileItem::IsType(const char *ext) const
1051 if (!m_strDynPath.empty())
1052 return URIUtils::HasExtension(m_strDynPath, ext);
1054 return URIUtils::HasExtension(m_strPath, ext);
1057 bool CFileItem::IsNFO() const
1059 return URIUtils::HasExtension(m_strPath, ".nfo");
1062 bool CFileItem::IsDiscImage() const
1064 return URIUtils::IsDiscImage(GetDynPath());
1067 bool CFileItem::IsOpticalMediaFile() const
1069 if (VIDEO::IsDVDFile(*this, false, true))
1070 return true;
1072 return VIDEO::IsBDFile(*this);
1075 bool CFileItem::IsRAR() const
1077 return URIUtils::IsRAR(m_strPath);
1080 bool CFileItem::IsAPK() const
1082 return URIUtils::IsAPK(m_strPath);
1085 bool CFileItem::IsZIP() const
1087 return URIUtils::IsZIP(m_strPath);
1090 bool CFileItem::IsCBZ() const
1092 return URIUtils::HasExtension(m_strPath, ".cbz");
1095 bool CFileItem::IsCBR() const
1097 return URIUtils::HasExtension(m_strPath, ".cbr");
1100 bool CFileItem::IsRSS() const
1102 return StringUtils::StartsWithNoCase(m_strPath, "rss://") || URIUtils::HasExtension(m_strPath, ".rss")
1103 || StringUtils::StartsWithNoCase(m_strPath, "rsss://")
1104 || m_mimetype == "application/rss+xml";
1107 bool CFileItem::IsAndroidApp() const
1109 return URIUtils::IsAndroidApp(m_strPath);
1112 bool CFileItem::IsStack() const
1114 return URIUtils::IsStack(GetDynPath());
1117 bool CFileItem::IsFavourite() const
1119 return URIUtils::IsFavourite(m_strPath);
1122 bool CFileItem::IsPlugin() const
1124 return URIUtils::IsPlugin(m_strPath);
1127 bool CFileItem::IsScript() const
1129 return URIUtils::IsScript(m_strPath);
1132 bool CFileItem::IsAddonsPath() const
1134 return URIUtils::IsAddonsPath(m_strPath);
1137 bool CFileItem::IsSourcesPath() const
1139 return URIUtils::IsSourcesPath(m_strPath);
1142 bool CFileItem::IsMultiPath() const
1144 return URIUtils::IsMultiPath(m_strPath);
1147 bool CFileItem::IsBluray() const
1149 if (URIUtils::IsBluray(m_strPath))
1150 return true;
1152 CFileItem item = CFileItem(VIDEO::UTILS::GetOpticalMediaPath(*this), false);
1154 return VIDEO::IsBDFile(item);
1157 bool CFileItem::IsDVD() const
1159 return URIUtils::IsDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1162 bool CFileItem::IsOnDVD() const
1164 return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1167 bool CFileItem::IsNfs() const
1169 return URIUtils::IsNfs(m_strPath);
1172 bool CFileItem::IsISO9660() const
1174 return URIUtils::IsISO9660(m_strPath);
1177 bool CFileItem::IsSmb() const
1179 return URIUtils::IsSmb(m_strPath);
1182 bool CFileItem::IsURL() const
1184 return URIUtils::IsURL(m_strPath);
1187 bool CFileItem::IsPVR() const
1189 return URIUtils::IsPVR(m_strPath);
1192 bool CFileItem::IsLiveTV() const
1194 return URIUtils::IsLiveTV(m_strPath);
1197 bool CFileItem::IsHD() const
1199 return URIUtils::IsHD(m_strPath);
1202 bool CFileItem::IsVirtualDirectoryRoot() const
1204 return (m_bIsFolder && m_strPath.empty());
1207 bool CFileItem::IsRemovable() const
1209 return IsOnDVD() || MUSIC::IsCDDA(*this) || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE;
1212 bool CFileItem::IsReadOnly() const
1214 if (IsParentFolder())
1215 return true;
1217 if (m_bIsShareOrDrive)
1218 return true;
1220 return !CUtil::SupportsWriteFileOperations(m_strPath);
1223 void CFileItem::RemoveExtension()
1225 if (m_bIsFolder)
1226 return;
1228 std::string strLabel = GetLabel();
1229 URIUtils::RemoveExtension(strLabel);
1230 SetLabel(strLabel);
1233 void CFileItem::CleanString()
1235 if (IsLiveTV())
1236 return;
1238 std::string strLabel = GetLabel();
1239 std::string strTitle, strTitleAndYear, strYear;
1240 CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, true);
1241 SetLabel(strTitleAndYear);
1244 void CFileItem::SetLabel(const std::string &strLabel)
1246 if (strLabel == "..")
1248 m_bIsParentFolder = true;
1249 m_bIsFolder = true;
1250 m_specialSort = SortSpecialOnTop;
1251 SetLabelPreformatted(true);
1253 CGUIListItem::SetLabel(strLabel);
1256 void CFileItem::SetFileSizeLabel()
1258 if(m_bIsFolder && m_dwSize == 0)
1259 SetLabel2("");
1260 else
1261 SetLabel2(StringUtils::SizeToString(m_dwSize));
1264 bool CFileItem::CanQueue() const
1266 return m_bCanQueue;
1269 void CFileItem::SetCanQueue(bool bYesNo)
1271 m_bCanQueue = bYesNo;
1274 bool CFileItem::IsParentFolder() const
1276 return m_bIsParentFolder;
1279 void CFileItem::FillInMimeType(bool lookup /*= true*/)
1281 //! @todo adapt this to use CMime::GetMimeType()
1282 if (m_mimetype.empty())
1284 if (m_bIsFolder)
1285 m_mimetype = "x-directory/normal";
1286 else if (HasPVRChannelInfoTag())
1287 m_mimetype = GetPVRChannelInfoTag()->MimeType();
1288 else if (StringUtils::StartsWithNoCase(GetDynPath(), "shout://") ||
1289 StringUtils::StartsWithNoCase(GetDynPath(), "http://") ||
1290 StringUtils::StartsWithNoCase(GetDynPath(), "https://"))
1292 // If lookup is false, bail out early to leave mime type empty
1293 if (!lookup)
1294 return;
1296 CCurlFile::GetMimeType(GetDynURL(), m_mimetype);
1298 // try to get mime-type again but with an NSPlayer User-Agent
1299 // in order for server to provide correct mime-type. Allows us
1300 // to properly detect an MMS stream
1301 if (StringUtils::StartsWithNoCase(m_mimetype, "video/x-ms-"))
1302 CCurlFile::GetMimeType(GetDynURL(), m_mimetype, "NSPlayer/11.00.6001.7000");
1304 // make sure there are no options set in mime-type
1305 // mime-type can look like "video/x-ms-asf ; charset=utf8"
1306 size_t i = m_mimetype.find(';');
1307 if(i != std::string::npos)
1308 m_mimetype.erase(i, m_mimetype.length() - i);
1309 StringUtils::Trim(m_mimetype);
1311 else
1312 m_mimetype = CMime::GetMimeType(*this);
1314 // if it's still empty set to an unknown type
1315 if (m_mimetype.empty())
1316 m_mimetype = "application/octet-stream";
1319 // change protocol to mms for the following mime-type. Allows us to create proper FileMMS.
1320 if(StringUtils::StartsWithNoCase(m_mimetype, "application/vnd.ms.wms-hdr.asfv1") ||
1321 StringUtils::StartsWithNoCase(m_mimetype, "application/x-mms-framed"))
1323 if (m_strDynPath.empty())
1324 m_strDynPath = m_strPath;
1326 StringUtils::Replace(m_strDynPath, "http:", "mms:");
1330 void CFileItem::UpdateMimeType(bool lookup /*= true*/)
1332 //! @todo application/octet-stream might actually have been set by a web lookup. Currently we
1333 //! cannot distinguish between set as fallback only (see FillInMimeType) or as an actual value.
1334 if (m_mimetype == "application/octet-stream")
1335 m_mimetype.clear();
1337 FillInMimeType(lookup);
1340 void CFileItem::SetMimeTypeForInternetFile()
1342 if (m_doContentLookup && NETWORK::IsInternetStream(*this))
1344 SetMimeType("");
1345 FillInMimeType(true);
1349 bool CFileItem::IsSamePath(const CFileItem *item) const
1351 if (!item)
1352 return false;
1354 if (!m_strPath.empty() && item->GetPath() == m_strPath)
1356 if (item->HasProperty("item_start") || HasProperty("item_start"))
1357 return (item->GetProperty("item_start") == GetProperty("item_start"));
1358 // See if we have associated a bluray playlist
1359 if (VIDEO::IsBlurayPlaylist(*this) || VIDEO::IsBlurayPlaylist(*item))
1360 return (GetDynPath() == item->GetDynPath());
1361 return true;
1363 if (HasMusicInfoTag() && item->HasMusicInfoTag())
1365 if (GetMusicInfoTag()->GetDatabaseId() != -1 && item->GetMusicInfoTag()->GetDatabaseId() != -1)
1366 return ((GetMusicInfoTag()->GetDatabaseId() == item->GetMusicInfoTag()->GetDatabaseId()) &&
1367 (GetMusicInfoTag()->GetType() == item->GetMusicInfoTag()->GetType()));
1369 if (HasVideoInfoTag() && item->HasVideoInfoTag())
1371 const CVideoInfoTag* myTag{GetVideoInfoTag()};
1372 const CVideoInfoTag* otherTag{item->GetVideoInfoTag()};
1373 if (myTag->m_iDbId != -1 && otherTag->m_iDbId != -1)
1375 if ((myTag->m_iDbId == otherTag->m_iDbId) && (myTag->m_type == otherTag->m_type))
1377 // for movies with multiple versions, wie need also to check the file id
1378 if (HasVideoVersions() && item->HasVideoVersions() && myTag->m_iFileId != -1 &&
1379 otherTag->m_iFileId != -1)
1380 return myTag->m_iFileId == otherTag->m_iFileId;
1381 return true;
1385 if (MUSIC::IsMusicDb(*this) && HasMusicInfoTag())
1387 CFileItem dbItem(m_musicInfoTag->GetURL(), false);
1388 if (HasProperty("item_start"))
1389 dbItem.SetProperty("item_start", GetProperty("item_start"));
1390 return dbItem.IsSamePath(item);
1392 if (VIDEO::IsVideoDb(*this) && HasVideoInfoTag())
1394 CFileItem dbItem(GetVideoInfoTag()->m_strFileNameAndPath, false);
1395 if (HasProperty("item_start"))
1396 dbItem.SetProperty("item_start", GetProperty("item_start"));
1397 return dbItem.IsSamePath(item);
1399 if (MUSIC::IsMusicDb(*item) && item->HasMusicInfoTag())
1401 CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
1402 if (item->HasProperty("item_start"))
1403 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1404 return IsSamePath(&dbItem);
1406 if (VIDEO::IsVideoDb(*item) && item->HasVideoInfoTag())
1408 CFileItem dbItem(item->GetVideoInfoTag()->m_strFileNameAndPath, false);
1409 if (item->HasProperty("item_start"))
1410 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1411 return IsSamePath(&dbItem);
1413 if (HasProperty("original_listitem_url"))
1414 return (GetProperty("original_listitem_url") == item->GetPath());
1415 return false;
1418 bool CFileItem::IsAlbum() const
1420 return m_bIsAlbum;
1423 void CFileItem::UpdateInfo(const CFileItem &item, bool replaceLabels /*=true*/)
1425 if (item.HasVideoInfoTag())
1426 { // copy info across
1427 //! @todo premiered info is normally stored in m_dateTime by the db
1429 if (item.m_videoInfoTag)
1431 if (m_videoInfoTag)
1432 *m_videoInfoTag = *item.m_videoInfoTag;
1433 else
1434 m_videoInfoTag = new CVideoInfoTag(*item.m_videoInfoTag);
1436 else
1438 if (m_videoInfoTag)
1439 delete m_videoInfoTag;
1441 m_videoInfoTag = new CVideoInfoTag;
1444 m_pvrRecordingInfoTag = item.m_pvrRecordingInfoTag;
1446 SetOverlayImage(GetVideoInfoTag()->GetPlayCount() > 0 ? CGUIListItem::ICON_OVERLAY_WATCHED
1447 : CGUIListItem::ICON_OVERLAY_UNWATCHED);
1448 SetInvalid();
1450 if (item.HasMusicInfoTag())
1452 *GetMusicInfoTag() = *item.GetMusicInfoTag();
1453 SetInvalid();
1455 if (item.HasPictureInfoTag())
1457 *GetPictureInfoTag() = *item.GetPictureInfoTag();
1458 SetInvalid();
1460 if (item.HasGameInfoTag())
1462 *GetGameInfoTag() = *item.GetGameInfoTag();
1463 SetInvalid();
1465 if (item.HasPVRChannelGroupMemberInfoTag())
1467 m_pvrChannelGroupMemberInfoTag = item.GetPVRChannelGroupMemberInfoTag();
1468 SetInvalid();
1470 if (item.HasPVRTimerInfoTag())
1472 m_pvrTimerInfoTag = item.m_pvrTimerInfoTag;
1473 SetInvalid();
1475 if (item.HasPVRProviderInfoTag())
1477 m_pvrProviderInfoTag = item.m_pvrProviderInfoTag;
1478 SetInvalid();
1480 if (item.HasEPGInfoTag())
1482 m_epgInfoTag = item.m_epgInfoTag;
1483 SetInvalid();
1485 if (item.HasEPGSearchFilter())
1487 m_epgSearchFilter = item.m_epgSearchFilter;
1488 SetInvalid();
1490 SetDynPath(item.GetDynPath());
1491 if (replaceLabels && !item.GetLabel().empty())
1492 SetLabel(item.GetLabel());
1493 if (replaceLabels && !item.GetLabel2().empty())
1494 SetLabel2(item.GetLabel2());
1495 if (!item.GetArt().empty())
1496 SetArt(item.GetArt());
1497 AppendProperties(item);
1499 SetContentLookup(item.m_doContentLookup);
1500 SetMimeType(item.m_mimetype);
1501 UpdateMimeType(m_doContentLookup);
1504 void CFileItem::MergeInfo(const CFileItem& item)
1506 // TODO: Currently merge the metadata/art info is implemented for video case only
1507 if (item.HasVideoInfoTag())
1509 if (item.m_videoInfoTag)
1511 if (m_videoInfoTag)
1512 m_videoInfoTag->Merge(*item.m_videoInfoTag);
1513 else
1514 m_videoInfoTag = new CVideoInfoTag(*item.m_videoInfoTag);
1517 m_pvrRecordingInfoTag = item.m_pvrRecordingInfoTag;
1519 SetOverlayImage(GetVideoInfoTag()->GetPlayCount() > 0 ? CGUIListItem::ICON_OVERLAY_WATCHED
1520 : CGUIListItem::ICON_OVERLAY_UNWATCHED);
1521 SetInvalid();
1523 if (item.HasMusicInfoTag())
1525 *GetMusicInfoTag() = *item.GetMusicInfoTag();
1526 SetInvalid();
1528 if (item.HasPictureInfoTag())
1530 *GetPictureInfoTag() = *item.GetPictureInfoTag();
1531 SetInvalid();
1533 if (item.HasGameInfoTag())
1535 *GetGameInfoTag() = *item.GetGameInfoTag();
1536 SetInvalid();
1538 if (item.HasPVRChannelGroupMemberInfoTag())
1540 m_pvrChannelGroupMemberInfoTag = item.GetPVRChannelGroupMemberInfoTag();
1541 SetInvalid();
1543 if (item.HasPVRTimerInfoTag())
1545 m_pvrTimerInfoTag = item.m_pvrTimerInfoTag;
1546 SetInvalid();
1548 if (item.HasPVRProviderInfoTag())
1550 m_pvrProviderInfoTag = item.m_pvrProviderInfoTag;
1551 SetInvalid();
1553 if (item.HasEPGInfoTag())
1555 m_epgInfoTag = item.m_epgInfoTag;
1556 SetInvalid();
1558 if (item.HasEPGSearchFilter())
1560 m_epgSearchFilter = item.m_epgSearchFilter;
1561 SetInvalid();
1563 SetDynPath(item.GetDynPath());
1564 if (!item.GetLabel().empty())
1565 SetLabel(item.GetLabel());
1566 if (!item.GetLabel2().empty())
1567 SetLabel2(item.GetLabel2());
1568 if (!item.GetArt().empty())
1570 if (VIDEO::IsVideo(item))
1571 AppendArt(item.GetArt());
1572 else
1573 SetArt(item.GetArt());
1575 AppendProperties(item);
1577 SetContentLookup(item.m_doContentLookup);
1578 SetMimeType(item.m_mimetype);
1579 UpdateMimeType(m_doContentLookup);
1582 void CFileItem::SetFromVideoInfoTag(const CVideoInfoTag &video)
1584 if (!video.m_strTitle.empty())
1585 SetLabel(video.m_strTitle);
1586 if (video.m_strFileNameAndPath.empty())
1588 m_strPath = video.m_strPath;
1589 URIUtils::AddSlashAtEnd(m_strPath);
1590 m_bIsFolder = true;
1592 else
1594 m_strPath = video.m_strFileNameAndPath;
1595 m_bIsFolder = false;
1598 if (m_videoInfoTag)
1599 *m_videoInfoTag = video;
1600 else
1601 m_videoInfoTag = new CVideoInfoTag(video);
1603 if (video.m_iSeason == 0)
1604 SetProperty("isspecial", "true");
1605 ART::FillInDefaultIcon(*this);
1606 FillInMimeType(false);
1609 namespace
1611 class CPropertySaveHelper
1613 public:
1614 CPropertySaveHelper(CFileItem& item, const std::string& property, const std::string& value)
1615 : m_item(item), m_property(property), m_value(value)
1619 bool NeedsSave() const { return !m_value.empty() || m_item.HasProperty(m_property); }
1621 std::string GetValueToSave(const std::string& currentValue) const
1623 std::string value;
1625 if (!m_value.empty())
1627 // Overwrite whatever we have; remember what we had originally.
1628 if (!m_item.HasProperty(m_property))
1629 m_item.SetProperty(m_property, currentValue);
1631 value = m_value;
1633 else if (m_item.HasProperty(m_property))
1635 // Restore original value
1636 value = m_item.GetProperty(m_property).asString();
1637 m_item.ClearProperty(m_property);
1640 return value;
1643 private:
1644 CFileItem& m_item;
1645 const std::string m_property;
1646 const std::string m_value;
1648 } // unnamed namespace
1650 void CFileItem::SetFromMusicInfoTag(const MUSIC_INFO::CMusicInfoTag& music)
1652 const std::string path = GetPath();
1653 if (path.empty())
1655 SetPath(music.GetURL());
1657 else
1659 const CPropertySaveHelper dynpath(*this, "OriginalDynPath", music.GetURL());
1660 if (dynpath.NeedsSave())
1661 SetDynPath(dynpath.GetValueToSave(m_strDynPath));
1664 const CPropertySaveHelper label(*this, "OriginalLabel", music.GetTitle());
1665 if (label.NeedsSave())
1666 SetLabel(label.GetValueToSave(GetLabel()));
1668 const CPropertySaveHelper thumb(*this, "OriginalThumb", music.GetStationArt());
1669 if (thumb.NeedsSave())
1670 SetArt("thumb", thumb.GetValueToSave(GetArt("thumb")));
1672 *GetMusicInfoTag() = music;
1673 ART::FillInDefaultIcon(*this);
1674 FillInMimeType(false);
1677 void CFileItem::SetFromAlbum(const CAlbum &album)
1679 if (!album.strAlbum.empty())
1680 SetLabel(album.strAlbum);
1681 m_bIsFolder = true;
1682 m_strLabel2 = album.GetAlbumArtistString();
1683 GetMusicInfoTag()->SetAlbum(album);
1685 if (album.art.empty())
1686 SetArt("icon", "DefaultAlbumCover.png");
1687 else
1688 SetArt(album.art);
1690 m_bIsAlbum = true;
1691 CMusicDatabase::SetPropertiesFromAlbum(*this,album);
1692 FillInMimeType(false);
1695 void CFileItem::SetFromSong(const CSong &song)
1697 if (!song.strTitle.empty())
1698 SetLabel(song.strTitle);
1699 if (song.idSong > 0)
1701 std::string strExt = URIUtils::GetExtension(song.strFileName);
1702 m_strPath = StringUtils::Format("musicdb://songs/{}{}", song.idSong, strExt);
1704 else if (!song.strFileName.empty())
1705 m_strPath = song.strFileName;
1706 GetMusicInfoTag()->SetSong(song);
1707 m_lStartOffset = song.iStartOffset;
1708 m_lStartPartNumber = 1;
1709 SetProperty("item_start", song.iStartOffset);
1710 m_lEndOffset = song.iEndOffset;
1711 if (!song.strThumb.empty())
1712 SetArt("thumb", song.strThumb);
1713 FillInMimeType(false);
1717 * @todo Ideally this (and SetPath) would not be available outside of construction
1718 * for CFileItem objects, or at least restricted to essentially be equivalent
1719 * to construction. This would require re-formulating a bunch of CFileItem
1720 * construction, and also allowing CFileItemList to have its own (public)
1721 * SetURL() function, so for now we give direct access.
1723 void CFileItem::SetURL(const CURL& url)
1725 m_strPath = url.Get();
1728 const CURL CFileItem::GetURL() const
1730 CURL url(m_strPath);
1731 return url;
1734 bool CFileItem::IsURL(const CURL& url) const
1736 return IsPath(url.Get());
1739 bool CFileItem::IsPath(const std::string& path, bool ignoreURLOptions /* = false */) const
1741 return URIUtils::PathEquals(m_strPath, path, false, ignoreURLOptions);
1744 void CFileItem::SetDynURL(const CURL& url)
1746 m_strDynPath = url.Get();
1749 const CURL CFileItem::GetDynURL() const
1751 if (!m_strDynPath.empty())
1753 CURL url(m_strDynPath);
1754 return url;
1756 else
1758 CURL url(m_strPath);
1759 return url;
1763 const std::string &CFileItem::GetDynPath() const
1765 if (!m_strDynPath.empty())
1766 return m_strDynPath;
1767 else
1768 return m_strPath;
1771 void CFileItem::SetDynPath(const std::string &path)
1773 m_strDynPath = path;
1776 std::string CFileItem::GetBlurayPath() const
1778 if (VIDEO::IsBlurayPlaylist(*this))
1780 CURL url(GetDynPath());
1781 CURL url2(url.GetHostName()); // strip bluray://
1782 if (url2.IsProtocol("udf"))
1783 // ISO
1784 return url2.GetHostName(); // strip udf://
1785 else if (url.IsProtocol("bluray"))
1786 // BDMV
1787 return url2.Get() + "BDMV/index.bdmv";
1789 return GetDynPath();
1792 void CFileItem::SetCueDocument(const CCueDocumentPtr& cuePtr)
1794 m_cueDocument = cuePtr;
1797 void CFileItem::LoadEmbeddedCue()
1799 CMusicInfoTag& tag = *GetMusicInfoTag();
1800 if (!tag.Loaded())
1801 return;
1803 const std::string embeddedCue = tag.GetCueSheet();
1804 if (!embeddedCue.empty())
1806 CCueDocumentPtr cuesheet(new CCueDocument);
1807 if (cuesheet->ParseTag(embeddedCue))
1809 std::vector<std::string> MediaFileVec;
1810 cuesheet->GetMediaFiles(MediaFileVec);
1811 for (std::vector<std::string>::iterator itMedia = MediaFileVec.begin();
1812 itMedia != MediaFileVec.end(); ++itMedia)
1813 cuesheet->UpdateMediaFile(*itMedia, GetPath());
1814 SetCueDocument(cuesheet);
1816 // Clear cuesheet tag having added it to item
1817 tag.SetCueSheet("");
1821 bool CFileItem::HasCueDocument() const
1823 return (m_cueDocument.get() != nullptr);
1826 bool CFileItem::LoadTracksFromCueDocument(CFileItemList& scannedItems)
1828 if (!m_cueDocument)
1829 return false;
1831 bool result = m_cueDocument->LoadTracks(scannedItems, *this);
1832 m_cueDocument.reset();
1834 return result;
1837 std::string CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */, bool fallbackToFolder /* = false */) const
1839 if (m_strPath.empty() || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://") ||
1840 StringUtils::StartsWithNoCase(m_strPath, "newplaylist://") || m_bIsShareOrDrive ||
1841 NETWORK::IsInternetStream(*this) || URIUtils::IsUPnP(m_strPath) ||
1842 (URIUtils::IsFTP(m_strPath) &&
1843 !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs) ||
1844 IsPlugin() || IsAddonsPath() || IsLibraryFolder() || IsParentFolder() ||
1845 MUSIC::IsMusicDb(*this))
1846 return "";
1848 // we first check for <filename>.tbn or <foldername>.tbn
1849 std::string fileThumb(ART::GetTBNFile(*this));
1850 if (CFile::Exists(fileThumb))
1851 return fileThumb;
1853 // Fall back to folder thumb, if requested
1854 if (!m_bIsFolder && fallbackToFolder)
1856 CFileItem item(URIUtils::GetDirectory(m_strPath), true);
1857 return item.GetUserMusicThumb(alwaysCheckRemote);
1860 // if a folder, check for folder.jpg
1861 if (m_bIsFolder && !IsFileFolder() &&
1862 (!NETWORK::IsRemote(*this) || alwaysCheckRemote ||
1863 CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
1864 CSettings::SETTING_MUSICFILES_FINDREMOTETHUMBS)))
1866 std::vector<CVariant> thumbs = CServiceBroker::GetSettingsComponent()->GetSettings()->GetList(
1867 CSettings::SETTING_MUSICLIBRARY_MUSICTHUMBS);
1868 for (const auto& i : thumbs)
1870 std::string strFileName = i.asString();
1871 std::string folderThumb(ART::GetFolderThumb(*this, strFileName));
1872 if (CFile::Exists(folderThumb)) // folder.jpg
1873 return folderThumb;
1874 size_t period = strFileName.find_last_of('.');
1875 if (period != std::string::npos)
1877 std::string ext;
1878 std::string name = strFileName;
1879 std::string folderThumb1 = folderThumb;
1880 name.erase(period);
1881 ext = strFileName.substr(period);
1882 StringUtils::ToUpper(ext);
1883 StringUtils::Replace(folderThumb1, strFileName, name + ext);
1884 if (CFile::Exists(folderThumb1)) // folder.JPG
1885 return folderThumb1;
1887 folderThumb1 = folderThumb;
1888 std::string firstletter = name.substr(0, 1);
1889 StringUtils::ToUpper(firstletter);
1890 name.replace(0, 1, firstletter);
1891 StringUtils::Replace(folderThumb1, strFileName, name + ext);
1892 if (CFile::Exists(folderThumb1)) // Folder.JPG
1893 return folderThumb1;
1895 folderThumb1 = folderThumb;
1896 StringUtils::ToLower(ext);
1897 StringUtils::Replace(folderThumb1, strFileName, name + ext);
1898 if (CFile::Exists(folderThumb1)) // Folder.jpg
1899 return folderThumb1;
1903 // No thumb found
1904 return "";
1907 bool CFileItem::SkipLocalArt() const
1909 return (m_strPath.empty() || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://") ||
1910 StringUtils::StartsWithNoCase(m_strPath, "newplaylist://") || m_bIsShareOrDrive ||
1911 NETWORK::IsInternetStream(*this) || URIUtils::IsUPnP(m_strPath) ||
1912 (URIUtils::IsFTP(m_strPath) &&
1913 !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bFTPThumbs) ||
1914 IsPlugin() || IsAddonsPath() || IsLibraryFolder() || IsParentFolder() || IsLiveTV() ||
1915 IsPVRRecording() || IsDVD());
1918 std::string CFileItem::GetThumbHideIfUnwatched(const CFileItem* item) const
1920 const std::shared_ptr<CSettingList> setting(std::dynamic_pointer_cast<CSettingList>(
1921 CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(
1922 CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS)));
1923 if (setting && item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_type == MediaTypeEpisode &&
1924 item->GetVideoInfoTag()->GetPlayCount() == 0 &&
1925 !CSettingUtils::FindIntInList(setting,
1926 CSettings::VIDEOLIBRARY_THUMB_SHOW_UNWATCHED_EPISODE) &&
1927 item->HasArt("thumb"))
1929 std::string fanArt = item->GetArt("fanart");
1930 if (fanArt.empty())
1931 return "OverlaySpoiler.png";
1932 else
1933 return fanArt;
1936 return item->GetArt("thumb");
1939 std::string CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) const
1941 if (SkipLocalArt())
1942 return "";
1944 std::string thumb;
1945 if (!m_bIsFolder)
1947 thumb = GetLocalArt(artFile, false);
1948 if (!thumb.empty() && CFile::Exists(thumb))
1949 return thumb;
1951 if ((useFolder || (m_bIsFolder && !IsFileFolder())) && !artFile.empty())
1953 std::string thumb2 = GetLocalArt(artFile, true);
1954 if (!thumb2.empty() && thumb2 != thumb && CFile::Exists(thumb2))
1955 return thumb2;
1957 return "";
1960 std::string CFileItem::GetLocalArtBaseFilename() const
1962 bool useFolder = false;
1963 return GetLocalArtBaseFilename(useFolder);
1966 std::string CFileItem::GetLocalArtBaseFilename(bool& useFolder) const
1968 std::string strFile;
1969 if (IsStack())
1971 std::string strPath;
1972 URIUtils::GetParentPath(m_strPath,strPath);
1973 strFile = URIUtils::AddFileToFolder(
1974 strPath, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(m_strPath)));
1977 std::string file = strFile.empty() ? m_strPath : strFile;
1978 if (URIUtils::IsInRAR(file) || URIUtils::IsInZIP(file))
1980 std::string strPath = URIUtils::GetDirectory(file);
1981 std::string strParent;
1982 URIUtils::GetParentPath(strPath,strParent);
1983 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(file));
1986 if (IsMultiPath())
1987 strFile = CMultiPathDirectory::GetFirstPath(m_strPath);
1989 if (IsOpticalMediaFile())
1990 { // optical media files should be treated like folders
1991 useFolder = true;
1992 strFile = GetLocalMetadataPath();
1994 else if (useFolder && !(m_bIsFolder && !IsFileFolder()))
1996 file = strFile.empty() ? m_strPath : strFile;
1997 strFile = URIUtils::GetDirectory(file);
2000 if (strFile.empty())
2001 strFile = GetDynPath();
2003 return strFile;
2006 std::string CFileItem::GetLocalArt(const std::string& artFile, bool useFolder) const
2008 // no retrieving of empty art files from folders
2009 if (useFolder && artFile.empty())
2010 return "";
2012 std::string strFile = GetLocalArtBaseFilename(useFolder);
2013 if (strFile.empty()) // empty filepath -> nothing to find
2014 return "";
2016 if (useFolder)
2018 if (!artFile.empty())
2019 return URIUtils::AddFileToFolder(strFile, artFile);
2021 else
2023 if (artFile.empty()) // old thumbnail matching
2024 return URIUtils::ReplaceExtension(strFile, ".tbn");
2025 else
2026 return URIUtils::ReplaceExtension(strFile, "-" + artFile);
2028 return "";
2031 std::string CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const
2033 if (IsPlugin() && HasVideoInfoTag() && !GetVideoInfoTag()->m_strTitle.empty())
2034 return GetVideoInfoTag()->m_strTitle;
2036 if (IsLabelPreformatted())
2037 return GetLabel();
2039 if (m_pvrRecordingInfoTag)
2040 return m_pvrRecordingInfoTag->m_strTitle;
2041 else if (URIUtils::IsPVRRecording(m_strPath))
2043 std::string title = CPVRRecording::GetTitleFromURL(m_strPath);
2044 if (!title.empty())
2045 return title;
2048 std::string strMovieName;
2049 if (URIUtils::IsStack(m_strPath))
2050 strMovieName = CStackDirectory::GetStackedTitlePath(m_strPath);
2051 else
2052 strMovieName = GetBaseMoviePath(bUseFolderNames);
2054 URIUtils::RemoveSlashAtEnd(strMovieName);
2056 return CURL::Decode(URIUtils::GetFileName(strMovieName));
2059 std::string CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
2061 std::string strMovieName = m_strPath;
2063 if (IsMultiPath())
2064 strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
2066 if (IsOpticalMediaFile())
2067 return GetLocalMetadataPath();
2069 if (bUseFolderNames &&
2070 (!m_bIsFolder || URIUtils::IsInArchive(m_strPath) ||
2071 (HasVideoInfoTag() && GetVideoInfoTag()->m_iDbId > 0 && !CMediaTypes::IsContainer(GetVideoInfoTag()->m_type))))
2073 std::string name2(strMovieName);
2074 URIUtils::GetParentPath(name2,strMovieName);
2075 if (URIUtils::IsInArchive(m_strPath))
2077 // Try to get archive itself, if empty take path before
2078 name2 = CURL(m_strPath).GetHostName();
2079 if (name2.empty())
2080 name2 = strMovieName;
2082 URIUtils::GetParentPath(name2, strMovieName);
2085 // Remove trailing 'Disc n' path segment to get actual movie title
2086 strMovieName = CUtil::RemoveTrailingDiscNumberSegmentFromPath(strMovieName);
2089 return strMovieName;
2092 std::string CFileItem::GetLocalMetadataPath() const
2094 if (m_bIsFolder && !IsFileFolder())
2095 return m_strPath;
2097 std::string parent{};
2098 if (VIDEO::IsBlurayPlaylist(*this))
2099 parent = URIUtils::GetParentPath(GetBlurayPath());
2100 else
2101 parent = URIUtils::GetParentPath(m_strPath);
2102 std::string parentFolder(parent);
2103 URIUtils::RemoveSlashAtEnd(parentFolder);
2104 parentFolder = URIUtils::GetFileName(parentFolder);
2105 if (StringUtils::EqualsNoCase(parentFolder, "VIDEO_TS") || StringUtils::EqualsNoCase(parentFolder, "BDMV"))
2106 { // go back up another one
2107 parent = URIUtils::GetParentPath(parent);
2109 return parent;
2112 bool CFileItem::LoadMusicTag()
2114 // not audio
2115 if (!MUSIC::IsAudio(*this))
2116 return false;
2117 // already loaded?
2118 if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
2119 return true;
2120 // check db
2121 CMusicDatabase musicDatabase;
2122 if (musicDatabase.Open())
2124 CSong song;
2125 if (musicDatabase.GetSongByFileName(m_strPath, song))
2127 GetMusicInfoTag()->SetSong(song);
2128 return true;
2130 musicDatabase.Close();
2132 // load tag from file
2133 CLog::Log(LOGDEBUG, "{}: loading tag information for file: {}", __FUNCTION__, m_strPath);
2134 CMusicInfoTagLoaderFactory factory;
2135 std::unique_ptr<IMusicInfoTagLoader> pLoader (factory.CreateLoader(*this));
2136 if (pLoader)
2138 if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
2139 return true;
2141 // no tag - try some other things
2142 if (MUSIC::IsCDDA(*this))
2144 // we have the tracknumber...
2145 int iTrack = GetMusicInfoTag()->GetTrackNumber();
2146 if (iTrack >= 1)
2148 std::string strText = g_localizeStrings.Get(554); // "Track"
2149 if (!strText.empty() && strText[strText.size() - 1] != ' ')
2150 strText += " ";
2151 std::string strTrack = StringUtils::Format((strText + "{}"), iTrack);
2152 GetMusicInfoTag()->SetTitle(strTrack);
2153 GetMusicInfoTag()->SetLoaded(true);
2154 return true;
2157 else
2159 std::string fileName = URIUtils::GetFileName(m_strPath);
2160 URIUtils::RemoveExtension(fileName);
2161 for (const std::string& fileFilter : CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicTagsFromFileFilters)
2163 CLabelFormatter formatter(fileFilter, "");
2164 if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
2166 GetMusicInfoTag()->SetLoaded(true);
2167 return true;
2171 return false;
2174 bool CFileItem::LoadGameTag()
2176 // Already loaded?
2177 if (HasGameInfoTag() && m_gameInfoTag->IsLoaded())
2178 return true;
2180 //! @todo
2181 GetGameInfoTag();
2183 m_gameInfoTag->SetLoaded(true);
2185 return false;
2188 bool CFileItem::LoadDetails()
2190 if (VIDEO::IsVideoDb(*this))
2192 if (HasVideoInfoTag())
2193 return true;
2195 CVideoDatabase db;
2196 if (!db.Open())
2198 CLog::LogF(LOGERROR, "Error opening video database");
2199 return false;
2202 VIDEODATABASEDIRECTORY::CQueryParams params;
2203 VIDEODATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(GetPath(), params);
2205 bool ret{false};
2206 auto tag{std::make_unique<CVideoInfoTag>()};
2207 if (params.GetMovieId() >= 0)
2208 ret = db.GetMovieInfo({}, *tag, static_cast<int>(params.GetMovieId()),
2209 static_cast<int>(params.GetVideoVersionId()));
2210 else if (params.GetMVideoId() >= 0)
2211 ret = db.GetMusicVideoInfo({}, *tag, static_cast<int>(params.GetMVideoId()));
2212 else if (params.GetEpisodeId() >= 0)
2213 ret = db.GetEpisodeInfo({}, *tag, static_cast<int>(params.GetEpisodeId()));
2214 else if (params.GetSetId() >= 0) // movie set
2215 ret = db.GetSetInfo(static_cast<int>(params.GetSetId()), *tag, this);
2216 else if (params.GetTvShowId() >= 0)
2218 if (params.GetSeason() >= 0)
2220 const int idSeason = db.GetSeasonId(static_cast<int>(params.GetTvShowId()),
2221 static_cast<int>(params.GetSeason()));
2222 if (idSeason >= 0)
2223 ret = db.GetSeasonInfo(idSeason, *tag, this);
2225 else
2226 ret = db.GetTvShowInfo({}, *tag, static_cast<int>(params.GetTvShowId()), this);
2229 if (ret)
2231 const CFileItem loadedItem{*tag};
2232 UpdateInfo(loadedItem);
2234 return ret;
2237 if (IsPVR())
2239 const std::shared_ptr<CFileItem> loadedItem{
2240 CServiceBroker::GetPVRManager().Get<PVR::GUI::Utils>().LoadItem(*this)};
2241 if (loadedItem)
2243 UpdateInfo(*loadedItem);
2244 return true;
2246 CLog::LogF(LOGERROR, "Error filling PVR item details (path={})", GetPath());
2247 return false;
2250 if (!PLAYLIST::IsPlayList(*this) && VIDEO::IsVideo(*this))
2252 if (HasVideoInfoTag())
2253 return true;
2255 CVideoDatabase db;
2256 if (!db.Open())
2258 CLog::LogF(LOGERROR, "Error opening video database");
2259 return false;
2262 auto tag{std::make_unique<CVideoInfoTag>()};
2263 if (db.LoadVideoInfo(GetDynPath(), *tag))
2265 const CFileItem loadedItem{*tag};
2266 UpdateInfo(loadedItem);
2267 return true;
2270 CLog::LogF(LOGERROR, "Error filling item details (path={})", GetPath());
2271 return false;
2274 if (PLAYLIST::IsPlayList(*this) && IsType(".strm"))
2276 const std::unique_ptr<PLAYLIST::CPlayList> playlist(PLAYLIST::CPlayListFactory::Create(*this));
2277 if (playlist)
2279 if (playlist->Load(GetPath()) && playlist->size() == 1)
2281 const auto item{(*playlist)[0]};
2282 if (VIDEO::IsVideo(*item))
2284 CVideoDatabase db;
2285 if (!db.Open())
2287 CLog::LogF(LOGERROR, "Error opening video database");
2288 return false;
2291 CVideoInfoTag tag;
2292 if (db.LoadVideoInfo(GetDynPath(), tag))
2294 UpdateInfo(*item);
2295 *GetVideoInfoTag() = tag;
2296 return true;
2299 else if (MUSIC::IsAudio(*item))
2301 if (item->LoadMusicTag())
2303 UpdateInfo(*item);
2304 return true;
2309 CLog::LogF(LOGERROR, "Error loading strm file details (path={})", GetPath());
2310 return false;
2313 if (MUSIC::IsAudio(*this))
2315 return LoadMusicTag();
2318 if (MUSIC::IsMusicDb(*this))
2320 if (HasMusicInfoTag())
2321 return true;
2323 CMusicDatabase db;
2324 if (!db.Open())
2326 CLog::LogF(LOGERROR, "Error opening music database");
2327 return false;
2330 MUSICDATABASEDIRECTORY::CQueryParams params;
2331 MUSICDATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(GetPath(), params);
2333 if (params.GetSongId() >= 0)
2335 CSong song;
2336 if (db.GetSong(params.GetSongId(), song))
2338 GetMusicInfoTag()->SetSong(song);
2339 return true;
2342 else if (params.GetAlbumId() >= 0)
2344 m_bIsFolder = true;
2345 CAlbum album;
2346 if (db.GetAlbum(params.GetAlbumId(), album, false))
2348 GetMusicInfoTag()->SetAlbum(album);
2349 return true;
2352 else if (params.GetArtistId() >= 0)
2354 m_bIsFolder = true;
2355 CArtist artist;
2356 if (db.GetArtist(params.GetArtistId(), artist, false))
2358 GetMusicInfoTag()->SetArtist(artist);
2359 return true;
2362 return false;
2365 //! @todo add support for other types on demand.
2366 CLog::LogF(LOGDEBUG, "Unsupported item type (path={})", GetPath());
2367 return false;
2370 bool CFileItem::HasVideoInfoTag() const
2372 // Note: CPVRRecording is derived from CVideoInfoTag
2373 return m_pvrRecordingInfoTag.get() != nullptr || m_videoInfoTag != nullptr;
2376 CVideoInfoTag* CFileItem::GetVideoInfoTag()
2378 // Note: CPVRRecording is derived from CVideoInfoTag
2379 if (m_pvrRecordingInfoTag)
2380 return m_pvrRecordingInfoTag.get();
2381 else if (!m_videoInfoTag)
2382 m_videoInfoTag = new CVideoInfoTag;
2384 return m_videoInfoTag;
2387 const CVideoInfoTag* CFileItem::GetVideoInfoTag() const
2389 // Note: CPVRRecording is derived from CVideoInfoTag
2390 return m_pvrRecordingInfoTag ? m_pvrRecordingInfoTag.get() : m_videoInfoTag;
2393 CPictureInfoTag* CFileItem::GetPictureInfoTag()
2395 if (!m_pictureInfoTag)
2396 m_pictureInfoTag = new CPictureInfoTag;
2398 return m_pictureInfoTag;
2401 MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
2403 if (!m_musicInfoTag)
2404 m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
2406 return m_musicInfoTag;
2409 CGameInfoTag* CFileItem::GetGameInfoTag()
2411 if (!m_gameInfoTag)
2412 m_gameInfoTag = new CGameInfoTag;
2414 return m_gameInfoTag;
2417 bool CFileItem::HasPVRChannelInfoTag() const
2419 return m_pvrChannelGroupMemberInfoTag && m_pvrChannelGroupMemberInfoTag->Channel() != nullptr;
2422 const std::shared_ptr<PVR::CPVRChannel> CFileItem::GetPVRChannelInfoTag() const
2424 return m_pvrChannelGroupMemberInfoTag ? m_pvrChannelGroupMemberInfoTag->Channel()
2425 : std::shared_ptr<CPVRChannel>();
2428 std::string CFileItem::FindTrailer() const
2430 std::string strFile2;
2431 std::string strFile = m_strPath;
2432 if (IsStack())
2434 std::string strPath;
2435 URIUtils::GetParentPath(m_strPath,strPath);
2436 CStackDirectory dir;
2437 std::string strPath2;
2438 strPath2 = dir.GetStackedTitlePath(strFile);
2439 strFile = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2));
2440 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
2441 std::string strTBNFile(URIUtils::ReplaceExtension(ART::GetTBNFile(item), "-trailer"));
2442 strFile2 = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile));
2444 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2446 std::string strPath = URIUtils::GetDirectory(strFile);
2447 std::string strParent;
2448 URIUtils::GetParentPath(strPath,strParent);
2449 strFile = URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath));
2452 // no local trailer available for these
2453 if (NETWORK::IsInternetStream(*this) || URIUtils::IsUPnP(strFile) ||
2454 URIUtils::IsBluray(strFile) || IsLiveTV() || IsPlugin() || IsDVD())
2455 return "";
2457 std::string strDir = URIUtils::GetDirectory(strFile);
2458 CFileItemList items;
2459 CDirectory::GetDirectory(strDir, items, CServiceBroker::GetFileExtensionProvider().GetVideoExtensions(), DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO | DIR_FLAG_NO_FILE_DIRS);
2460 URIUtils::RemoveExtension(strFile);
2461 strFile += "-trailer";
2462 std::string strFile3 = URIUtils::AddFileToFolder(strDir, "movie-trailer");
2464 // Precompile our REs
2465 VECCREGEXP matchRegExps;
2466 CRegExp tmpRegExp(true, CRegExp::autoUtf8);
2467 const std::vector<std::string>& strMatchRegExps = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_trailerMatchRegExps;
2469 std::vector<std::string>::const_iterator strRegExp = strMatchRegExps.begin();
2470 while (strRegExp != strMatchRegExps.end())
2472 if (tmpRegExp.RegComp(*strRegExp))
2474 matchRegExps.push_back(tmpRegExp);
2476 ++strRegExp;
2479 std::string strTrailer;
2480 for (int i = 0; i < items.Size(); i++)
2482 std::string strCandidate = items[i]->m_strPath;
2483 URIUtils::RemoveExtension(strCandidate);
2484 if (StringUtils::EqualsNoCase(strCandidate, strFile) ||
2485 StringUtils::EqualsNoCase(strCandidate, strFile2) ||
2486 StringUtils::EqualsNoCase(strCandidate, strFile3))
2488 strTrailer = items[i]->m_strPath;
2489 break;
2491 else
2493 VECCREGEXP::iterator expr = matchRegExps.begin();
2495 while (expr != matchRegExps.end())
2497 if (expr->RegFind(strCandidate) != -1)
2499 strTrailer = items[i]->m_strPath;
2500 i = items.Size();
2501 break;
2503 ++expr;
2508 return strTrailer;
2511 VideoDbContentType CFileItem::GetVideoContentType() const
2513 VideoDbContentType type = VideoDbContentType::MOVIES;
2514 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type == MediaTypeTvShow)
2515 type = VideoDbContentType::TVSHOWS;
2516 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type == MediaTypeEpisode)
2517 return VideoDbContentType::EPISODES;
2518 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type == MediaTypeMusicVideo)
2519 return VideoDbContentType::MUSICVIDEOS;
2520 if (HasVideoInfoTag() && GetVideoInfoTag()->m_type == MediaTypeAlbum)
2521 return VideoDbContentType::MUSICALBUMS;
2523 CVideoDatabaseDirectory dir;
2524 VIDEODATABASEDIRECTORY::CQueryParams params;
2525 dir.GetQueryParams(m_strPath, params);
2526 if (params.GetSetId() != -1 && params.GetMovieId() == -1) // movie set
2527 return VideoDbContentType::MOVIE_SETS;
2529 return type;
2532 CFileItem CFileItem::GetItemToPlay() const
2534 if (HasEPGInfoTag())
2536 const std::shared_ptr<CPVRChannelGroupMember> groupMember =
2537 CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(*this);
2538 if (groupMember)
2539 return CFileItem(groupMember);
2541 return *this;
2544 CBookmark CFileItem::GetResumePoint() const
2546 if (HasVideoInfoTag())
2547 return GetVideoInfoTag()->GetResumePoint();
2548 return CBookmark();
2551 bool CFileItem::IsResumePointSet() const
2553 return GetResumePoint().IsSet();
2556 double CFileItem::GetCurrentResumeTime() const
2558 return lrint(GetResumePoint().timeInSeconds);
2561 bool CFileItem::GetCurrentResumeTimeAndPartNumber(int64_t& startOffset, int& partNumber) const
2563 CBookmark resumePoint(GetResumePoint());
2564 if (resumePoint.IsSet())
2566 startOffset = llrint(resumePoint.timeInSeconds);
2567 partNumber = resumePoint.partNumber;
2568 return true;
2570 return false;
2573 bool CFileItem::IsResumable() const
2575 if (m_bIsFolder)
2577 int64_t watched = 0;
2578 int64_t inprogress = 0;
2579 int64_t total = 0;
2580 if (HasProperty("inprogressepisodes"))
2582 // show/season
2583 watched = GetProperty("watchedepisodes").asInteger();
2584 inprogress = GetProperty("inprogressepisodes").asInteger();
2585 total = GetProperty("totalepisodes").asInteger();
2587 else if (HasProperty("inprogress"))
2589 // movie set
2590 watched = GetProperty("watched").asInteger();
2591 inprogress = GetProperty("inprogress").asInteger();
2592 total = GetProperty("total").asInteger();
2595 return ((total != watched) && (inprogress > 0 || watched != 0));
2597 else
2599 return HasVideoInfoTag() && GetVideoInfoTag()->GetResumePoint().IsPartWay();
2603 bool CFileItem::HasVideoVersions() const
2605 if (HasVideoInfoTag())
2607 return GetVideoInfoTag()->HasVideoVersions();
2609 return false;
2612 bool CFileItem::HasVideoExtras() const
2614 if (HasVideoInfoTag())
2616 return GetVideoInfoTag()->HasVideoExtras();
2618 return false;