2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #include "guilib/LocalizeStrings.h"
23 #include "utils/StringUtils.h"
24 #include "utils/URIUtils.h"
26 #include "playlists/PlayListFactory.h"
27 #include "utils/Crc32.h"
28 #include "filesystem/Directory.h"
29 #include "filesystem/StackDirectory.h"
30 #include "filesystem/CurlFile.h"
31 #include "filesystem/MultiPathDirectory.h"
32 #include "filesystem/MusicDatabaseDirectory.h"
33 #include "filesystem/VideoDatabaseDirectory.h"
34 #include "filesystem/VideoDatabaseDirectory/QueryParams.h"
35 #include "music/tags/MusicInfoTagLoaderFactory.h"
36 #include "CueDocument.h"
37 #include "video/VideoDatabase.h"
38 #include "music/MusicDatabase.h"
39 #include "utils/TuxBoxUtil.h"
41 #include "pvr/channels/PVRChannel.h"
42 #include "pvr/recordings/PVRRecording.h"
43 #include "pvr/timers/PVRTimerInfoTag.h"
44 #include "utils/Observer.h"
45 #include "video/VideoInfoTag.h"
46 #include "threads/SingleLock.h"
47 #include "music/tags/MusicInfoTag.h"
48 #include "pictures/PictureInfoTag.h"
49 #include "music/Artist.h"
50 #include "music/Album.h"
51 #include "music/Song.h"
53 #include "settings/AdvancedSettings.h"
54 #include "settings/Settings.h"
55 #include "utils/RegExp.h"
56 #include "utils/log.h"
57 #include "utils/Variant.h"
58 #include "music/karaoke/karaokelyricsfactory.h"
59 #include "utils/Mime.h"
61 #include "cores/paplayer/ASAPCodec.h"
65 using namespace XFILE;
66 using namespace PLAYLIST;
67 using namespace MUSIC_INFO;
71 CFileItem::CFileItem(const CSong& song)
73 m_musicInfoTag = NULL;
74 m_videoInfoTag = NULL;
76 m_pvrChannelInfoTag = NULL;
77 m_pvrRecordingInfoTag = NULL;
78 m_pvrTimerInfoTag = NULL;
79 m_pictureInfoTag = NULL;
85 CFileItem::CFileItem(const CStdString &path, const CAlbum& album)
87 m_musicInfoTag = NULL;
88 m_videoInfoTag = NULL;
90 m_pvrChannelInfoTag = NULL;
91 m_pvrRecordingInfoTag = NULL;
92 m_pvrTimerInfoTag = NULL;
93 m_pictureInfoTag = NULL;
97 URIUtils::AddSlashAtEnd(m_strPath);
101 CFileItem::CFileItem(const CMusicInfoTag& music)
103 m_musicInfoTag = NULL;
104 m_videoInfoTag = NULL;
106 m_pvrChannelInfoTag = NULL;
107 m_pvrRecordingInfoTag = NULL;
108 m_pvrTimerInfoTag = NULL;
109 m_pictureInfoTag = NULL;
111 SetLabel(music.GetTitle());
112 m_strPath = music.GetURL();
113 m_bIsFolder = URIUtils::HasSlashAtEnd(m_strPath);
114 *GetMusicInfoTag() = music;
116 FillInMimeType(false);
119 CFileItem::CFileItem(const CVideoInfoTag& movie)
121 m_musicInfoTag = NULL;
122 m_videoInfoTag = NULL;
124 m_pvrChannelInfoTag = NULL;
125 m_pvrRecordingInfoTag = NULL;
126 m_pvrTimerInfoTag = NULL;
127 m_pictureInfoTag = NULL;
130 SetFromVideoInfoTag(movie);
133 CFileItem::CFileItem(const CEpgInfoTag& tag)
135 m_musicInfoTag = NULL;
136 m_videoInfoTag = NULL;
138 m_pvrChannelInfoTag = NULL;
139 m_pvrRecordingInfoTag = NULL;
140 m_pvrTimerInfoTag = NULL;
141 m_pictureInfoTag = NULL;
145 m_strPath = tag.Path();
147 *GetEPGInfoTag() = tag;
148 SetLabel(tag.Title());
149 m_strLabel2 = tag.Plot();
150 m_dateTime = tag.StartAsLocalTime();
152 if (!tag.Icon().empty())
153 SetIconImage(tag.Icon());
154 else if (tag.HasPVRChannel() && !tag.ChannelTag()->IconPath().empty())
155 SetIconImage(tag.ChannelTag()->IconPath());
157 FillInMimeType(false);
160 CFileItem::CFileItem(const CPVRChannel& channel)
162 m_musicInfoTag = NULL;
163 m_videoInfoTag = NULL;
165 m_pvrChannelInfoTag = NULL;
166 m_pvrRecordingInfoTag = NULL;
167 m_pvrTimerInfoTag = NULL;
168 m_pictureInfoTag = NULL;
172 bool bHasEpgNow = channel.GetEPGNow(epgNow);
174 m_strPath = channel.Path();
176 *GetPVRChannelInfoTag() = channel;
177 SetLabel(channel.ChannelName());
178 m_strLabel2 = bHasEpgNow ? epgNow.Title() :
179 CSettings::Get().GetBool("epg.hidenoinfoavailable") ?
180 StringUtils::EmptyString :
181 g_localizeStrings.Get(19055); // no information available
183 if (channel.IsRadio())
185 CMusicInfoTag* musictag = GetMusicInfoTag();
188 musictag->SetURL(channel.Path());
189 musictag->SetTitle(m_strLabel2);
190 musictag->SetArtist(channel.ChannelName());
191 musictag->SetAlbumArtist(channel.ChannelName());
193 musictag->SetGenre(epgNow.Genre());
194 musictag->SetDuration(bHasEpgNow ? epgNow.GetDuration() : 3600);
195 musictag->SetLoaded(true);
196 musictag->SetComment("");
197 musictag->SetLyrics("");
201 if (!channel.IconPath().empty())
202 SetIconImage(channel.IconPath());
204 SetProperty("channelid", channel.ChannelID());
205 SetProperty("path", channel.Path());
206 SetArt("thumb", channel.IconPath());
208 FillInMimeType(false);
211 CFileItem::CFileItem(const CPVRRecording& record)
213 m_musicInfoTag = NULL;
214 m_videoInfoTag = NULL;
216 m_pvrChannelInfoTag = NULL;
217 m_pvrRecordingInfoTag = NULL;
218 m_pvrTimerInfoTag = NULL;
219 m_pictureInfoTag = NULL;
223 m_strPath = record.m_strFileNameAndPath;
225 *GetPVRRecordingInfoTag() = record;
226 SetLabel(record.m_strTitle);
227 m_strLabel2 = record.m_strPlot;
229 FillInMimeType(false);
232 CFileItem::CFileItem(const CPVRTimerInfoTag& timer)
234 m_musicInfoTag = NULL;
235 m_videoInfoTag = NULL;
237 m_pvrChannelInfoTag = NULL;
238 m_pvrRecordingInfoTag = NULL;
239 m_pvrTimerInfoTag = NULL;
240 m_pictureInfoTag = NULL;
244 m_strPath = timer.Path();
246 *GetPVRTimerInfoTag() = timer;
247 SetLabel(timer.Title());
248 m_strLabel2 = timer.Summary();
249 m_dateTime = timer.StartAsLocalTime();
251 if (!timer.ChannelIcon().empty())
252 SetIconImage(timer.ChannelIcon());
254 FillInMimeType(false);
257 CFileItem::CFileItem(const CArtist& artist)
259 m_musicInfoTag = NULL;
260 m_videoInfoTag = NULL;
262 m_pvrChannelInfoTag = NULL;
263 m_pvrRecordingInfoTag = NULL;
264 m_pvrTimerInfoTag = NULL;
265 m_pictureInfoTag = NULL;
267 SetLabel(artist.strArtist);
268 m_strPath = artist.strArtist;
270 URIUtils::AddSlashAtEnd(m_strPath);
271 GetMusicInfoTag()->SetArtist(artist.strArtist);
272 FillInMimeType(false);
275 CFileItem::CFileItem(const CGenre& genre)
277 m_musicInfoTag = NULL;
278 m_videoInfoTag = NULL;
280 m_pvrChannelInfoTag = NULL;
281 m_pvrRecordingInfoTag = NULL;
282 m_pvrTimerInfoTag = NULL;
283 m_pictureInfoTag = NULL;
285 SetLabel(genre.strGenre);
286 m_strPath = genre.strGenre;
288 URIUtils::AddSlashAtEnd(m_strPath);
289 GetMusicInfoTag()->SetGenre(genre.strGenre);
290 FillInMimeType(false);
293 CFileItem::CFileItem(const CFileItem& item): CGUIListItem()
295 m_musicInfoTag = NULL;
296 m_videoInfoTag = NULL;
298 m_pvrChannelInfoTag = NULL;
299 m_pvrRecordingInfoTag = NULL;
300 m_pvrTimerInfoTag = NULL;
301 m_pictureInfoTag = NULL;
305 CFileItem::CFileItem(const CGUIListItem& item)
307 m_musicInfoTag = NULL;
308 m_videoInfoTag = NULL;
310 m_pvrChannelInfoTag = NULL;
311 m_pvrRecordingInfoTag = NULL;
312 m_pvrTimerInfoTag = NULL;
313 m_pictureInfoTag = NULL;
315 // not particularly pretty, but it gets around the issue of Reset() defaulting
316 // parameters in the CGUIListItem base class.
317 *((CGUIListItem *)this) = item;
319 FillInMimeType(false);
322 CFileItem::CFileItem(void)
324 m_musicInfoTag = NULL;
325 m_videoInfoTag = NULL;
327 m_pvrChannelInfoTag = NULL;
328 m_pvrRecordingInfoTag = NULL;
329 m_pvrTimerInfoTag = NULL;
330 m_pictureInfoTag = NULL;
334 CFileItem::CFileItem(const CStdString& strLabel)
337 m_musicInfoTag = NULL;
338 m_videoInfoTag = NULL;
340 m_pvrChannelInfoTag = NULL;
341 m_pvrRecordingInfoTag = NULL;
342 m_pvrTimerInfoTag = NULL;
343 m_pictureInfoTag = NULL;
348 CFileItem::CFileItem(const CStdString& strPath, bool bIsFolder)
350 m_musicInfoTag = NULL;
351 m_videoInfoTag = NULL;
353 m_pvrChannelInfoTag = NULL;
354 m_pvrRecordingInfoTag = NULL;
355 m_pvrTimerInfoTag = NULL;
356 m_pictureInfoTag = NULL;
359 m_bIsFolder = bIsFolder;
360 // tuxbox urls cannot have a / at end
361 if (m_bIsFolder && !m_strPath.empty() && !IsFileFolder() && !URIUtils::IsTuxBox(m_strPath))
362 URIUtils::AddSlashAtEnd(m_strPath);
363 FillInMimeType(false);
366 CFileItem::CFileItem(const CMediaSource& share)
368 m_musicInfoTag = NULL;
369 m_videoInfoTag = NULL;
371 m_pvrChannelInfoTag = NULL;
372 m_pvrRecordingInfoTag = NULL;
373 m_pvrTimerInfoTag = NULL;
374 m_pictureInfoTag = NULL;
377 m_bIsShareOrDrive = true;
378 m_strPath = share.strPath;
379 if (!IsRSS()) // no slash at end for rss feeds
380 URIUtils::AddSlashAtEnd(m_strPath);
381 CStdString label = share.strName;
382 if (!share.strStatus.empty())
383 label = StringUtils::Format("%s (%s)", share.strName.c_str(), share.strStatus.c_str());
385 m_iLockMode = share.m_iLockMode;
386 m_strLockCode = share.m_strLockCode;
387 m_iHasLock = share.m_iHasLock;
388 m_iBadPwdCount = share.m_iBadPwdCount;
389 m_iDriveType = share.m_iDriveType;
390 SetArt("thumb", share.m_strThumbnailImage);
391 SetLabelPreformated(true);
393 GetVideoInfoTag()->m_strFileNameAndPath = share.strDiskUniqueId; // share.strDiskUniqueId contains disc unique id
394 FillInMimeType(false);
397 CFileItem::~CFileItem(void)
399 delete m_musicInfoTag;
400 delete m_videoInfoTag;
402 delete m_pvrChannelInfoTag;
403 delete m_pvrRecordingInfoTag;
404 delete m_pvrTimerInfoTag;
405 delete m_pictureInfoTag;
407 m_musicInfoTag = NULL;
408 m_videoInfoTag = NULL;
410 m_pvrChannelInfoTag = NULL;
411 m_pvrRecordingInfoTag = NULL;
412 m_pvrTimerInfoTag = NULL;
413 m_pictureInfoTag = NULL;
416 const CFileItem& CFileItem::operator=(const CFileItem& item)
418 if (this == &item) return * this;
419 CGUIListItem::operator=(item);
420 m_bLabelPreformated=item.m_bLabelPreformated;
422 m_strPath = item.GetPath();
423 m_bIsParentFolder = item.m_bIsParentFolder;
424 m_iDriveType = item.m_iDriveType;
425 m_bIsShareOrDrive = item.m_bIsShareOrDrive;
426 m_dateTime = item.m_dateTime;
427 m_dwSize = item.m_dwSize;
428 if (item.HasMusicInfoTag())
430 m_musicInfoTag = GetMusicInfoTag();
432 *m_musicInfoTag = *item.m_musicInfoTag;
436 delete m_musicInfoTag;
437 m_musicInfoTag = NULL;
440 if (item.HasVideoInfoTag())
442 m_videoInfoTag = GetVideoInfoTag();
444 *m_videoInfoTag = *item.m_videoInfoTag;
448 delete m_videoInfoTag;
449 m_videoInfoTag = NULL;
452 if (item.HasEPGInfoTag())
454 m_epgInfoTag = GetEPGInfoTag();
456 *m_epgInfoTag = *item.m_epgInfoTag;
466 if (item.HasPVRChannelInfoTag())
468 m_pvrChannelInfoTag = GetPVRChannelInfoTag();
469 if (m_pvrChannelInfoTag)
470 *m_pvrChannelInfoTag = *item.m_pvrChannelInfoTag;
474 if (m_pvrChannelInfoTag)
475 delete m_pvrChannelInfoTag;
477 m_pvrChannelInfoTag = NULL;
480 if (item.HasPVRRecordingInfoTag())
482 m_pvrRecordingInfoTag = GetPVRRecordingInfoTag();
483 if (m_pvrRecordingInfoTag)
484 *m_pvrRecordingInfoTag = *item.m_pvrRecordingInfoTag;
488 if (m_pvrRecordingInfoTag)
489 delete m_pvrRecordingInfoTag;
491 m_pvrRecordingInfoTag = NULL;
494 if (item.HasPVRTimerInfoTag())
496 m_pvrTimerInfoTag = GetPVRTimerInfoTag();
497 if (m_pvrTimerInfoTag)
498 *m_pvrTimerInfoTag = *item.m_pvrTimerInfoTag;
502 if (m_pvrTimerInfoTag)
503 delete m_pvrTimerInfoTag;
505 m_pvrTimerInfoTag = NULL;
508 if (item.HasPictureInfoTag())
510 m_pictureInfoTag = GetPictureInfoTag();
511 if (m_pictureInfoTag)
512 *m_pictureInfoTag = *item.m_pictureInfoTag;
516 delete m_pictureInfoTag;
517 m_pictureInfoTag = NULL;
520 m_lStartOffset = item.m_lStartOffset;
521 m_lStartPartNumber = item.m_lStartPartNumber;
522 m_lEndOffset = item.m_lEndOffset;
523 m_strDVDLabel = item.m_strDVDLabel;
524 m_strTitle = item.m_strTitle;
525 m_iprogramCount = item.m_iprogramCount;
526 m_idepth = item.m_idepth;
527 m_iLockMode = item.m_iLockMode;
528 m_strLockCode = item.m_strLockCode;
529 m_iHasLock = item.m_iHasLock;
530 m_iBadPwdCount = item.m_iBadPwdCount;
531 m_bCanQueue=item.m_bCanQueue;
532 m_mimetype = item.m_mimetype;
533 m_extrainfo = item.m_extrainfo;
534 m_specialSort = item.m_specialSort;
535 m_bIsAlbum = item.m_bIsAlbum;
539 void CFileItem::Reset()
543 m_bLabelPreformated=false;
545 m_overlayIcon = ICON_OVERLAY_NONE;
548 m_strDVDLabel.clear();
553 m_bIsParentFolder=false;
554 m_bIsShareOrDrive = false;
556 m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
558 m_lStartPartNumber = 1;
562 m_iLockMode = LOCK_MODE_EVERYONE;
568 delete m_musicInfoTag;
570 delete m_videoInfoTag;
574 delete m_pvrChannelInfoTag;
575 m_pvrChannelInfoTag=NULL;
576 delete m_pvrRecordingInfoTag;
577 m_pvrRecordingInfoTag=NULL;
578 delete m_pvrTimerInfoTag;
579 m_pvrTimerInfoTag=NULL;
580 delete m_pictureInfoTag;
581 m_pictureInfoTag=NULL;
583 m_specialSort = SortSpecialNone;
588 void CFileItem::Archive(CArchive& ar)
590 CGUIListItem::Archive(ar);
594 ar << m_bIsParentFolder;
595 ar << m_bLabelPreformated;
597 ar << m_bIsShareOrDrive;
603 ar << m_iprogramCount;
605 ar << m_lStartOffset;
606 ar << m_lStartPartNumber;
610 ar << m_iBadPwdCount;
620 ar << *m_musicInfoTag;
627 ar << *m_videoInfoTag;
631 if (m_pictureInfoTag)
634 ar << *m_pictureInfoTag;
641 ar >> m_bIsParentFolder;
642 ar >> m_bLabelPreformated;
644 ar >> m_bIsShareOrDrive;
650 ar >> m_iprogramCount;
652 ar >> m_lStartOffset;
653 ar >> m_lStartPartNumber;
657 m_iLockMode = (LockType)temp;
659 ar >> m_iBadPwdCount;
665 m_specialSort = (SortSpecial)temp;
670 ar >> *GetMusicInfoTag();
673 ar >> *GetVideoInfoTag();
676 ar >> *GetPictureInfoTag();
682 void CFileItem::Serialize(CVariant& value) const
684 //CGUIListItem::Serialize(value["CGUIListItem"]);
686 value["strPath"] = m_strPath;
687 value["dateTime"] = (m_dateTime.IsValid()) ? m_dateTime.GetAsRFC1123DateTime() : "";
688 value["lastmodified"] = m_dateTime.IsValid() ? m_dateTime.GetAsDBDateTime() : "";
689 value["size"] = m_dwSize;
690 value["DVDLabel"] = m_strDVDLabel;
691 value["title"] = m_strTitle;
692 value["mimetype"] = m_mimetype;
693 value["extrainfo"] = m_extrainfo;
696 (*m_musicInfoTag).Serialize(value["musicInfoTag"]);
699 (*m_videoInfoTag).Serialize(value["videoInfoTag"]);
701 if (m_pictureInfoTag)
702 (*m_pictureInfoTag).Serialize(value["pictureInfoTag"]);
705 void CFileItem::ToSortable(SortItem &sortable, Field field) const
709 case FieldPath: sortable[FieldPath] = m_strPath; break;
710 case FieldDate: sortable[FieldDate] = (m_dateTime.IsValid()) ? m_dateTime.GetAsDBDateTime() : ""; break;
711 case FieldSize: sortable[FieldSize] = m_dwSize; break;
712 case FieldDriveType: sortable[FieldDriveType] = m_iDriveType; break;
713 case FieldStartOffset: sortable[FieldStartOffset] = m_lStartOffset; break;
714 case FieldEndOffset: sortable[FieldEndOffset] = m_lEndOffset; break;
715 case FieldProgramCount: sortable[FieldProgramCount] = m_iprogramCount; break;
716 case FieldBitrate: sortable[FieldBitrate] = m_dwSize; break;
717 case FieldTitle: sortable[FieldTitle] = m_strTitle; break;
718 // If there's ever a need to convert more properties from CGUIListItem it might be
719 // worth to make CGUIListItem implement ISortable as well and call it from here
723 if (HasMusicInfoTag())
724 GetMusicInfoTag()->ToSortable(sortable, field);
726 if (HasVideoInfoTag())
728 GetVideoInfoTag()->ToSortable(sortable, field);
730 if (GetVideoInfoTag()->m_type == "tvshow")
732 if (field == FieldNumberOfEpisodes && HasProperty("totalepisodes"))
733 sortable[FieldNumberOfEpisodes] = GetProperty("totalepisodes");
734 if (field == FieldNumberOfWatchedEpisodes && HasProperty("unwatchedepisodes"))
735 sortable[FieldNumberOfWatchedEpisodes] = GetProperty("unwatchedepisodes");
739 if (HasPictureInfoTag())
740 GetPictureInfoTag()->ToSortable(sortable, field);
742 if (HasPVRChannelInfoTag())
743 GetPVRChannelInfoTag()->ToSortable(sortable, field);
746 void CFileItem::ToSortable(SortItem &sortable, const Fields &fields) const
748 Fields::const_iterator it;
749 for (it = fields.begin(); it != fields.end(); it++)
750 ToSortable(sortable, *it);
752 /* FieldLabel is used as a fallback by all sorters and therefore has to be present as well */
753 sortable[FieldLabel] = GetLabel();
754 /* FieldSortSpecial and FieldFolder are required in conjunction with all other sorters as well */
755 sortable[FieldSortSpecial] = m_specialSort;
756 sortable[FieldFolder] = m_bIsFolder;
759 bool CFileItem::Exists(bool bUseCache /* = true */) const
761 if (m_strPath.empty()
762 || m_strPath.Equals("add")
763 || IsInternetStream()
765 || IsVirtualDirectoryRoot()
769 if (IsVideoDb() && HasVideoInfoTag())
771 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
772 return dbItem.Exists();
775 CStdString strPath = m_strPath;
777 if (URIUtils::IsMultiPath(strPath))
778 strPath = CMultiPathDirectory::GetFirstPath(strPath);
780 if (URIUtils::IsStack(strPath))
781 strPath = CStackDirectory::GetFirstStackedFile(strPath);
784 return CDirectory::Exists(strPath);
786 return CFile::Exists(strPath, bUseCache);
791 bool CFileItem::IsVideo() const
793 /* check preset mime type */
794 if( StringUtils::StartsWithNoCase(m_mimetype, "video/") )
797 if (HasVideoInfoTag()) return true;
798 if (HasMusicInfoTag()) return false;
799 if (HasPictureInfoTag()) return false;
800 if (IsPVRRecording()) return true;
802 if (IsHDHomeRun() || IsTuxBox() || URIUtils::IsDVD(m_strPath) || IsSlingbox())
805 CStdString extension;
806 if( StringUtils::StartsWithNoCase(m_mimetype, "application/") )
807 { /* check for some standard types */
808 extension = m_mimetype.substr(12);
809 if( extension.Equals("ogg")
810 || extension.Equals("mp4")
811 || extension.Equals("mxf") )
815 return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_videoExtensions);
818 bool CFileItem::IsEPG() const
820 if (HasEPGInfoTag()) return true; /// is this enough?
824 bool CFileItem::IsPVRChannel() const
826 if (HasPVRChannelInfoTag()) return true; /// is this enough?
830 bool CFileItem::IsPVRRecording() const
832 if (HasPVRRecordingInfoTag()) return true; /// is this enough?
836 bool CFileItem::IsPVRTimer() const
838 if (HasPVRTimerInfoTag()) return true; /// is this enough?
842 bool CFileItem::IsDiscStub() const
844 if (IsVideoDb() && HasVideoInfoTag())
846 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
847 return dbItem.IsDiscStub();
850 return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_discStubExtensions);
853 bool CFileItem::IsAudio() const
855 /* check preset mime type */
856 if( StringUtils::StartsWithNoCase(m_mimetype, "audio/") )
859 if (HasMusicInfoTag()) return true;
860 if (HasVideoInfoTag()) return false;
861 if (HasPictureInfoTag()) return false;
862 if (IsCDDA()) return true;
864 if( StringUtils::StartsWithNoCase(m_mimetype, "application/") )
865 { /* check for some standard types */
866 CStdString extension = m_mimetype.substr(12);
867 if( extension.Equals("ogg")
868 || extension.Equals("mp4")
869 || extension.Equals("mxf") )
873 return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_musicExtensions);
876 bool CFileItem::IsKaraoke() const
881 return CKaraokeLyricsFactory::HasLyrics( m_strPath );
884 bool CFileItem::IsPicture() const
886 if( StringUtils::StartsWithNoCase(m_mimetype, "image/") )
889 if (HasPictureInfoTag()) return true;
890 if (HasMusicInfoTag()) return false;
891 if (HasVideoInfoTag()) return false;
893 return CUtil::IsPicture(m_strPath);
896 bool CFileItem::IsLyrics() const
898 return URIUtils::HasExtension(m_strPath, ".cdg|.lrc");
901 bool CFileItem::IsCUESheet() const
903 return URIUtils::HasExtension(m_strPath, ".cue");
906 bool CFileItem::IsInternetStream(const bool bStrictCheck /* = false */) const
908 if (HasProperty("IsHTTPDirectory"))
911 return URIUtils::IsInternetStream(m_strPath, bStrictCheck);
914 bool CFileItem::IsFileFolder(EFileFolderType types) const
916 EFileFolderType always_type = EFILEFOLDER_TYPE_ALWAYS;
918 /* internet streams are not directly expanded */
919 if(IsInternetStream())
920 always_type = EFILEFOLDER_TYPE_ONCLICK;
923 if(types & always_type)
925 if( IsSmartPlayList()
926 || (IsPlayList() && g_advancedSettings.m_playlistAsFolders)
931 || IsType(".ogg|.oga|.nsf|.sid|.sap|.xsp")
932 #if defined(TARGET_ANDROID)
935 #ifdef HAS_ASAP_CODEC
936 || ASAPCodec::IsSupportedFormat(URIUtils::GetExtension(m_strPath))
942 if(types & EFILEFOLDER_TYPE_ONBROWSE)
944 if((IsPlayList() && !g_advancedSettings.m_playlistAsFolders)
953 bool CFileItem::IsSmartPlayList() const
955 if (HasProperty("library.smartplaylist") && GetProperty("library.smartplaylist").asBoolean())
958 return URIUtils::HasExtension(m_strPath, ".xsp");
961 bool CFileItem::IsLibraryFolder() const
963 if (HasProperty("library.filter") && GetProperty("library.filter").asBoolean())
966 return URIUtils::IsLibraryFolder(m_strPath);
969 bool CFileItem::IsPlayList() const
971 return CPlayListFactory::IsPlaylist(*this);
974 bool CFileItem::IsPythonScript() const
976 return URIUtils::HasExtension(m_strPath, ".py");
979 bool CFileItem::IsType(const char *ext) const
981 return URIUtils::HasExtension(m_strPath, ext);
984 bool CFileItem::IsNFO() const
986 return URIUtils::HasExtension(m_strPath, ".nfo");
989 bool CFileItem::IsDVDImage() const
991 return URIUtils::HasExtension(m_strPath, ".img|.iso|.nrg");
994 bool CFileItem::IsOpticalMediaFile() const
996 bool found = IsDVDFile(false, true);
1002 bool CFileItem::IsDVDFile(bool bVobs /*= true*/, bool bIfos /*= true*/) const
1004 CStdString strFileName = URIUtils::GetFileName(m_strPath);
1007 if (strFileName.Equals("video_ts.ifo")) return true;
1008 if (StringUtils::StartsWithNoCase(strFileName, "vts_") && StringUtils::EndsWithNoCase(strFileName, "_0.ifo") && strFileName.length() == 12) return true;
1012 if (strFileName.Equals("video_ts.vob")) return true;
1013 if (StringUtils::StartsWithNoCase(strFileName, "vts_") && StringUtils::EndsWithNoCase(strFileName, ".vob")) return true;
1019 bool CFileItem::IsBDFile() const
1021 CStdString strFileName = URIUtils::GetFileName(m_strPath);
1022 return (strFileName.Equals("index.bdmv"));
1025 bool CFileItem::IsRAR() const
1027 return URIUtils::IsRAR(m_strPath);
1030 bool CFileItem::IsAPK() const
1032 return URIUtils::IsAPK(m_strPath);
1035 bool CFileItem::IsZIP() const
1037 return URIUtils::IsZIP(m_strPath);
1040 bool CFileItem::IsCBZ() const
1042 return URIUtils::HasExtension(m_strPath, ".cbz");
1045 bool CFileItem::IsCBR() const
1047 return URIUtils::HasExtension(m_strPath, ".cbr");
1050 bool CFileItem::IsRSS() const
1052 return StringUtils::StartsWithNoCase(m_strPath, "rss://") || URIUtils::HasExtension(m_strPath, ".rss")
1053 || m_mimetype == "application/rss+xml";
1056 bool CFileItem::IsAndroidApp() const
1058 return URIUtils::IsAndroidApp(m_strPath);
1061 bool CFileItem::IsStack() const
1063 return URIUtils::IsStack(m_strPath);
1066 bool CFileItem::IsPlugin() const
1068 return URIUtils::IsPlugin(m_strPath);
1071 bool CFileItem::IsScript() const
1073 return URIUtils::IsScript(m_strPath);
1076 bool CFileItem::IsAddonsPath() const
1078 return URIUtils::IsAddonsPath(m_strPath);
1081 bool CFileItem::IsSourcesPath() const
1083 return URIUtils::IsSourcesPath(m_strPath);
1086 bool CFileItem::IsMultiPath() const
1088 return URIUtils::IsMultiPath(m_strPath);
1091 bool CFileItem::IsCDDA() const
1093 return URIUtils::IsCDDA(m_strPath);
1096 bool CFileItem::IsDVD() const
1098 return URIUtils::IsDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1101 bool CFileItem::IsOnDVD() const
1103 return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1106 bool CFileItem::IsNfs() const
1108 return URIUtils::IsNfs(m_strPath);
1111 bool CFileItem::IsAfp() const
1113 return URIUtils::IsAfp(m_strPath);
1116 bool CFileItem::IsOnLAN() const
1118 return URIUtils::IsOnLAN(m_strPath);
1121 bool CFileItem::IsISO9660() const
1123 return URIUtils::IsISO9660(m_strPath);
1126 bool CFileItem::IsRemote() const
1128 return URIUtils::IsRemote(m_strPath);
1131 bool CFileItem::IsSmb() const
1133 return URIUtils::IsSmb(m_strPath);
1136 bool CFileItem::IsURL() const
1138 return URIUtils::IsURL(m_strPath);
1141 bool CFileItem::IsDAAP() const
1143 return URIUtils::IsDAAP(m_strPath);
1146 bool CFileItem::IsTuxBox() const
1148 return URIUtils::IsTuxBox(m_strPath);
1151 bool CFileItem::IsMythTV() const
1153 return URIUtils::IsMythTV(m_strPath);
1156 bool CFileItem::IsHDHomeRun() const
1158 return URIUtils::IsHDHomeRun(m_strPath);
1161 bool CFileItem::IsSlingbox() const
1163 return URIUtils::IsSlingbox(m_strPath);
1166 bool CFileItem::IsVTP() const
1168 return URIUtils::IsVTP(m_strPath);
1171 bool CFileItem::IsPVR() const
1173 return CUtil::IsPVR(m_strPath);
1176 bool CFileItem::IsLiveTV() const
1178 return URIUtils::IsLiveTV(m_strPath);
1181 bool CFileItem::IsHD() const
1183 return URIUtils::IsHD(m_strPath);
1186 bool CFileItem::IsMusicDb() const
1188 return URIUtils::IsMusicDb(m_strPath);
1191 bool CFileItem::IsVideoDb() const
1193 return URIUtils::IsVideoDb(m_strPath);
1196 bool CFileItem::IsVirtualDirectoryRoot() const
1198 return (m_bIsFolder && m_strPath.empty());
1201 bool CFileItem::IsRemovable() const
1203 return IsOnDVD() || IsCDDA() || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE;
1206 bool CFileItem::IsReadOnly() const
1208 if (IsParentFolder()) return true;
1209 if (m_bIsShareOrDrive) return true;
1210 return !CUtil::SupportsWriteFileOperations(m_strPath);
1213 void CFileItem::FillInDefaultIcon()
1215 //CLog::Log(LOGINFO, "FillInDefaultIcon(%s)", pItem->GetLabel().c_str());
1216 // find the default icon for a file or folder item
1217 // for files this can be the (depending on the file type)
1218 // default picture for photo's
1219 // default picture for songs
1220 // default picture for videos
1221 // default picture for shortcuts
1222 // default picture for playlists
1223 // or the icon embedded in an .xbe
1226 // for .. folders the default picture for parent folder
1227 // for other folders the defaultFolder.png
1229 if (GetIconImage().empty())
1233 /* To reduce the average runtime of this code, this list should
1234 * be ordered with most frequently seen types first. Also bear
1235 * in mind the complexity of the code behind the check in the
1236 * case of IsWhatater() returns false.
1240 if (GetPVRChannelInfoTag()->IsRadio())
1241 SetIconImage("DefaultAudio.png");
1243 SetIconImage("DefaultVideo.png");
1245 else if ( IsLiveTV() )
1248 SetIconImage("DefaultVideo.png");
1250 else if ( URIUtils::IsArchive(m_strPath) )
1252 SetIconImage("DefaultFile.png");
1254 else if ( IsAudio() )
1257 SetIconImage("DefaultAudio.png");
1259 else if ( IsVideo() )
1262 SetIconImage("DefaultVideo.png");
1264 else if (IsPVRRecording())
1266 SetIconImage("DefaultVideo.png");
1268 else if (IsPVRTimer())
1270 SetIconImage("DefaultVideo.png");
1272 else if ( IsPicture() )
1275 SetIconImage("DefaultPicture.png");
1277 else if ( IsPlayList() )
1279 SetIconImage("DefaultPlaylist.png");
1281 else if ( IsPythonScript() )
1283 SetIconImage("DefaultScript.png");
1287 // default icon for unknown file type
1288 SetIconImage("DefaultFile.png");
1295 SetIconImage("DefaultPlaylist.png");
1297 else if (IsParentFolder())
1299 SetIconImage("DefaultFolderBack.png");
1303 SetIconImage("DefaultFolder.png");
1307 // Set the icon overlays (if applicable)
1310 if (URIUtils::IsInRAR(m_strPath))
1311 SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR);
1312 else if (URIUtils::IsInZIP(m_strPath))
1313 SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP);
1317 void CFileItem::RemoveExtension()
1321 CStdString strLabel = GetLabel();
1322 URIUtils::RemoveExtension(strLabel);
1326 void CFileItem::CleanString()
1331 CStdString strLabel = GetLabel();
1332 CStdString strTitle, strTitleAndYear, strYear;
1333 CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, true );
1334 SetLabel(strTitleAndYear);
1337 void CFileItem::SetLabel(const CStdString &strLabel)
1341 m_bIsParentFolder=true;
1343 m_specialSort = SortSpecialOnTop;
1344 SetLabelPreformated(true);
1346 CGUIListItem::SetLabel(strLabel);
1349 void CFileItem::SetFileSizeLabel()
1351 if( m_bIsFolder && m_dwSize == 0 )
1354 SetLabel2(StringUtils::SizeToString(m_dwSize));
1357 CURL CFileItem::GetAsUrl() const
1359 return CURL(m_strPath);
1362 bool CFileItem::CanQueue() const
1367 void CFileItem::SetCanQueue(bool bYesNo)
1372 bool CFileItem::IsParentFolder() const
1374 return m_bIsParentFolder;
1377 void CFileItem::FillInMimeType(bool lookup /*= true*/)
1379 // TODO: adapt this to use CMime::GetMimeType()
1380 if (m_mimetype.empty())
1383 m_mimetype = "x-directory/normal";
1384 else if( m_pvrChannelInfoTag )
1385 m_mimetype = m_pvrChannelInfoTag->InputFormat();
1386 else if( StringUtils::StartsWithNoCase(m_strPath, "shout://")
1387 || StringUtils::StartsWithNoCase(m_strPath, "http://")
1388 || StringUtils::StartsWithNoCase(m_strPath, "https://"))
1390 // If lookup is false, bail out early to leave mime type empty
1394 CCurlFile::GetMimeType(GetAsUrl(), m_mimetype);
1396 // try to get mime-type again but with an NSPlayer User-Agent
1397 // in order for server to provide correct mime-type. Allows us
1398 // to properly detect an MMS stream
1399 if (StringUtils::StartsWithNoCase(m_mimetype, "video/x-ms-"))
1400 CCurlFile::GetMimeType(GetAsUrl(), m_mimetype, "NSPlayer/11.00.6001.7000");
1402 // make sure there are no options set in mime-type
1403 // mime-type can look like "video/x-ms-asf ; charset=utf8"
1404 size_t i = m_mimetype.find(';');
1405 if(i != std::string::npos)
1406 m_mimetype.erase(i, m_mimetype.length() - i);
1407 StringUtils::Trim(m_mimetype);
1410 m_mimetype = CMime::GetMimeType(*this);
1412 // if it's still empty set to an unknown type
1413 if (m_mimetype.empty())
1414 m_mimetype = "application/octet-stream";
1417 // change protocol to mms for the following mime-type. Allows us to create proper FileMMS.
1418 if( StringUtils::StartsWithNoCase(m_mimetype, "application/vnd.ms.wms-hdr.asfv1") || StringUtils::StartsWithNoCase(m_mimetype, "application/x-mms-framed") )
1419 StringUtils::Replace(m_strPath, "http:", "mms:");
1422 bool CFileItem::IsSamePath(const CFileItem *item) const
1427 if (item->GetPath() == m_strPath)
1429 if (item->HasProperty("item_start") || HasProperty("item_start"))
1430 return (item->GetProperty("item_start") == GetProperty("item_start"));
1433 if (HasVideoInfoTag() && item->HasVideoInfoTag())
1435 if (m_videoInfoTag->m_iDbId != -1 && item->m_videoInfoTag->m_iDbId != -1)
1436 return ((m_videoInfoTag->m_iDbId == item->m_videoInfoTag->m_iDbId) &&
1437 (m_videoInfoTag->m_type == item->m_videoInfoTag->m_type));
1439 if (IsMusicDb() && HasMusicInfoTag())
1441 CFileItem dbItem(m_musicInfoTag->GetURL(), false);
1442 if (HasProperty("item_start"))
1443 dbItem.SetProperty("item_start", GetProperty("item_start"));
1444 return dbItem.IsSamePath(item);
1446 if (IsVideoDb() && HasVideoInfoTag())
1448 CFileItem dbItem(m_videoInfoTag->m_strFileNameAndPath, false);
1449 if (HasProperty("item_start"))
1450 dbItem.SetProperty("item_start", GetProperty("item_start"));
1451 return dbItem.IsSamePath(item);
1453 if (item->IsMusicDb() && item->HasMusicInfoTag())
1455 CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
1456 if (item->HasProperty("item_start"))
1457 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1458 return IsSamePath(&dbItem);
1460 if (item->IsVideoDb() && item->HasVideoInfoTag())
1462 CFileItem dbItem(item->m_videoInfoTag->m_strFileNameAndPath, false);
1463 if (item->HasProperty("item_start"))
1464 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1465 return IsSamePath(&dbItem);
1467 if (HasProperty("original_listitem_url"))
1468 return (GetProperty("original_listitem_url") == item->GetPath());
1472 bool CFileItem::IsAlbum() const
1477 void CFileItem::UpdateInfo(const CFileItem &item, bool replaceLabels /*=true*/)
1479 if (item.HasVideoInfoTag())
1480 { // copy info across (TODO: premiered info is normally stored in m_dateTime by the db)
1481 *GetVideoInfoTag() = *item.GetVideoInfoTag();
1482 // preferably use some information from PVR info tag if available
1483 if (HasPVRRecordingInfoTag())
1484 GetPVRRecordingInfoTag()->CopyClientInfo(GetVideoInfoTag());
1485 SetOverlayImage(ICON_OVERLAY_UNWATCHED, GetVideoInfoTag()->m_playCount > 0);
1488 if (item.HasMusicInfoTag())
1490 *GetMusicInfoTag() = *item.GetMusicInfoTag();
1493 if (item.HasPictureInfoTag())
1495 *GetPictureInfoTag() = *item.GetPictureInfoTag();
1498 if (replaceLabels && !item.GetLabel().empty())
1499 SetLabel(item.GetLabel());
1500 if (replaceLabels && !item.GetLabel2().empty())
1501 SetLabel2(item.GetLabel2());
1502 if (!item.GetArt("thumb").empty())
1503 SetArt("thumb", item.GetArt("thumb"));
1504 if (!item.GetIconImage().empty())
1505 SetIconImage(item.GetIconImage());
1506 AppendProperties(item);
1509 void CFileItem::SetFromVideoInfoTag(const CVideoInfoTag &video)
1511 if (!video.m_strTitle.empty())
1512 SetLabel(video.m_strTitle);
1513 if (video.m_strFileNameAndPath.empty())
1515 m_strPath = video.m_strPath;
1516 URIUtils::AddSlashAtEnd(m_strPath);
1521 m_strPath = video.m_strFileNameAndPath;
1522 m_bIsFolder = false;
1525 *GetVideoInfoTag() = video;
1526 if (video.m_iSeason == 0)
1527 SetProperty("isspecial", "true");
1528 FillInDefaultIcon();
1529 FillInMimeType(false);
1532 void CFileItem::SetFromAlbum(const CAlbum &album)
1534 if (!album.strAlbum.empty())
1535 SetLabel(album.strAlbum);
1537 m_strLabel2 = StringUtils::Join(album.artist, g_advancedSettings.m_musicItemSeparator);
1538 GetMusicInfoTag()->SetAlbum(album);
1540 CMusicDatabase::SetPropertiesFromAlbum(*this,album);
1541 FillInMimeType(false);
1544 void CFileItem::SetFromSong(const CSong &song)
1546 if (!song.strTitle.empty())
1547 SetLabel(song.strTitle);
1548 if (!song.strFileName.empty())
1549 m_strPath = song.strFileName;
1550 GetMusicInfoTag()->SetSong(song);
1551 m_lStartOffset = song.iStartOffset;
1552 m_lStartPartNumber = 1;
1553 SetProperty("item_start", song.iStartOffset);
1554 m_lEndOffset = song.iEndOffset;
1555 if (!song.strThumb.empty())
1556 SetArt("thumb", song.strThumb);
1557 FillInMimeType(false);
1560 std::string CFileItem::GetOpticalMediaPath() const
1563 std::string dvdPath;
1564 path = URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS.IFO");
1565 if (CFile::Exists(path))
1569 dvdPath = URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS");
1570 path = URIUtils::AddFileToFolder(dvdPath, "VIDEO_TS.IFO");
1572 if (CFile::Exists(path))
1575 #ifdef HAVE_LIBBLURAY
1576 if (dvdPath.empty())
1578 path = URIUtils::AddFileToFolder(GetPath(), "index.bdmv");
1579 if (CFile::Exists(path))
1583 dvdPath = URIUtils::AddFileToFolder(GetPath(), "BDMV");
1584 path = URIUtils::AddFileToFolder(dvdPath, "index.bdmv");
1586 if (CFile::Exists(path))
1594 /////////////////////////////////////////////////////////////////////////////////
1598 //////////////////////////////////////////////////////////////////////////////////
1600 CFileItemList::CFileItemList()
1602 m_fastLookup = false;
1604 m_cacheToDisc = CACHE_IF_SLOW;
1605 m_sortIgnoreFolders = false;
1606 m_replaceListing = false;
1609 CFileItemList::CFileItemList(const CStdString& strPath) : CFileItem(strPath, true)
1611 m_fastLookup = false;
1612 m_cacheToDisc = CACHE_IF_SLOW;
1613 m_sortIgnoreFolders = false;
1614 m_replaceListing = false;
1617 CFileItemList::~CFileItemList()
1622 CFileItemPtr CFileItemList::operator[] (int iItem)
1627 const CFileItemPtr CFileItemList::operator[] (int iItem) const
1632 CFileItemPtr CFileItemList::operator[] (const CStdString& strPath)
1634 return Get(strPath);
1637 const CFileItemPtr CFileItemList::operator[] (const CStdString& strPath) const
1639 return Get(strPath);
1642 void CFileItemList::SetFastLookup(bool fastLookup)
1644 CSingleLock lock(m_lock);
1646 if (fastLookup && !m_fastLookup)
1647 { // generate the map
1649 for (unsigned int i=0; i < m_items.size(); i++)
1651 CFileItemPtr pItem = m_items[i];
1652 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1655 if (!fastLookup && m_fastLookup)
1657 m_fastLookup = fastLookup;
1660 bool CFileItemList::Contains(const CStdString& fileName) const
1662 CSingleLock lock(m_lock);
1665 return m_map.find(fileName) != m_map.end();
1668 for (unsigned int i = 0; i < m_items.size(); i++)
1670 const CFileItemPtr pItem = m_items[i];
1671 if (pItem->GetPath().Equals(fileName))
1677 void CFileItemList::Clear()
1679 CSingleLock lock(m_lock);
1682 m_sortDescription.sortBy = SortByNone;
1683 m_sortDescription.sortOrder = SortOrderNone;
1684 m_sortDescription.sortAttributes = SortAttributeNone;
1685 m_sortIgnoreFolders = false;
1686 m_cacheToDisc = CACHE_IF_SLOW;
1687 m_sortDetails.clear();
1688 m_replaceListing = false;
1692 void CFileItemList::ClearItems()
1694 CSingleLock lock(m_lock);
1695 // make sure we free the memory of the items (these are GUIControls which may have allocated resources)
1697 for (unsigned int i = 0; i < m_items.size(); i++)
1699 CFileItemPtr item = m_items[i];
1706 void CFileItemList::Add(const CFileItemPtr &pItem)
1708 CSingleLock lock(m_lock);
1710 m_items.push_back(pItem);
1713 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1717 void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition)
1719 CSingleLock lock(m_lock);
1721 if (itemPosition >= 0)
1723 m_items.insert(m_items.begin()+itemPosition, pItem);
1727 m_items.insert(m_items.begin()+(m_items.size()+itemPosition), pItem);
1731 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1735 void CFileItemList::Remove(CFileItem* pItem)
1737 CSingleLock lock(m_lock);
1739 for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it)
1741 if (pItem == it->get())
1746 m_map.erase(pItem->GetPath());
1753 void CFileItemList::Remove(int iItem)
1755 CSingleLock lock(m_lock);
1757 if (iItem >= 0 && iItem < (int)Size())
1759 CFileItemPtr pItem = *(m_items.begin() + iItem);
1762 m_map.erase(pItem->GetPath());
1764 m_items.erase(m_items.begin() + iItem);
1768 void CFileItemList::Append(const CFileItemList& itemlist)
1770 CSingleLock lock(m_lock);
1772 for (int i = 0; i < itemlist.Size(); ++i)
1776 void CFileItemList::Assign(const CFileItemList& itemlist, bool append)
1778 CSingleLock lock(m_lock);
1782 SetPath(itemlist.GetPath());
1783 SetLabel(itemlist.GetLabel());
1784 m_sortDetails = itemlist.m_sortDetails;
1785 m_sortDescription = itemlist.m_sortDescription;
1786 m_replaceListing = itemlist.m_replaceListing;
1787 m_content = itemlist.m_content;
1788 m_mapProperties = itemlist.m_mapProperties;
1789 m_cacheToDisc = itemlist.m_cacheToDisc;
1792 bool CFileItemList::Copy(const CFileItemList& items, bool copyItems /* = true */)
1794 // assign all CFileItem parts
1795 *(CFileItem*)this = *(CFileItem*)&items;
1797 // assign the rest of the CFileItemList properties
1798 m_replaceListing = items.m_replaceListing;
1799 m_content = items.m_content;
1800 m_mapProperties = items.m_mapProperties;
1801 m_cacheToDisc = items.m_cacheToDisc;
1802 m_sortDetails = items.m_sortDetails;
1803 m_sortDescription = items.m_sortDescription;
1804 m_sortIgnoreFolders = items.m_sortIgnoreFolders;
1808 // make a copy of each item
1809 for (int i = 0; i < items.Size(); i++)
1811 CFileItemPtr newItem(new CFileItem(*items[i]));
1819 CFileItemPtr CFileItemList::Get(int iItem)
1821 CSingleLock lock(m_lock);
1823 if (iItem > -1 && iItem < (int)m_items.size())
1824 return m_items[iItem];
1826 return CFileItemPtr();
1829 const CFileItemPtr CFileItemList::Get(int iItem) const
1831 CSingleLock lock(m_lock);
1833 if (iItem > -1 && iItem < (int)m_items.size())
1834 return m_items[iItem];
1836 return CFileItemPtr();
1839 CFileItemPtr CFileItemList::Get(const CStdString& strPath)
1841 CSingleLock lock(m_lock);
1845 IMAPFILEITEMS it=m_map.find(strPath);
1846 if (it != m_map.end())
1849 return CFileItemPtr();
1852 for (unsigned int i = 0; i < m_items.size(); i++)
1854 CFileItemPtr pItem = m_items[i];
1855 if (pItem->GetPath().Equals(strPath))
1859 return CFileItemPtr();
1862 const CFileItemPtr CFileItemList::Get(const CStdString& strPath) const
1864 CSingleLock lock(m_lock);
1868 map<CStdString, CFileItemPtr>::const_iterator it=m_map.find(strPath);
1869 if (it != m_map.end())
1872 return CFileItemPtr();
1875 for (unsigned int i = 0; i < m_items.size(); i++)
1877 CFileItemPtr pItem = m_items[i];
1878 if (pItem->GetPath().Equals(strPath))
1882 return CFileItemPtr();
1885 int CFileItemList::Size() const
1887 CSingleLock lock(m_lock);
1888 return (int)m_items.size();
1891 bool CFileItemList::IsEmpty() const
1893 CSingleLock lock(m_lock);
1894 return (m_items.size() <= 0);
1897 void CFileItemList::Reserve(int iCount)
1899 CSingleLock lock(m_lock);
1900 m_items.reserve(iCount);
1903 void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func)
1905 CSingleLock lock(m_lock);
1906 std::stable_sort(m_items.begin(), m_items.end(), func);
1909 void CFileItemList::FillSortFields(FILEITEMFILLFUNC func)
1911 CSingleLock lock(m_lock);
1912 std::for_each(m_items.begin(), m_items.end(), func);
1915 void CFileItemList::Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute sortAttributes /* = SortAttributeNone */)
1917 if (sortBy == SortByNone ||
1918 (m_sortDescription.sortBy == sortBy && m_sortDescription.sortOrder == sortOrder &&
1919 m_sortDescription.sortAttributes == sortAttributes))
1922 SortDescription sorting;
1923 sorting.sortBy = sortBy;
1924 sorting.sortOrder = sortOrder;
1925 sorting.sortAttributes = sortAttributes;
1928 m_sortDescription = sorting;
1931 void CFileItemList::Sort(SortDescription sortDescription)
1933 if (sortDescription.sortBy == SortByFile ||
1934 sortDescription.sortBy == SortBySortTitle ||
1935 sortDescription.sortBy == SortByDateAdded ||
1936 sortDescription.sortBy == SortByRating ||
1937 sortDescription.sortBy == SortByYear ||
1938 sortDescription.sortBy == SortByPlaylistOrder ||
1939 sortDescription.sortBy == SortByLastPlayed ||
1940 sortDescription.sortBy == SortByPlaycount)
1941 sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders);
1943 if (sortDescription.sortBy == SortByNone ||
1944 (m_sortDescription.sortBy == sortDescription.sortBy && m_sortDescription.sortOrder == sortDescription.sortOrder &&
1945 m_sortDescription.sortAttributes == sortDescription.sortAttributes))
1948 if (m_sortIgnoreFolders)
1949 sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders);
1951 const Fields fields = SortUtils::GetFieldsForSorting(sortDescription.sortBy);
1952 SortItems sortItems((size_t)Size());
1953 for (int index = 0; index < Size(); index++)
1955 sortItems[index] = boost::shared_ptr<SortItem>(new SortItem);
1956 m_items[index]->ToSortable(*sortItems[index], fields);
1957 (*sortItems[index])[FieldId] = index;
1961 SortUtils::Sort(sortDescription, sortItems);
1963 // apply the new order to the existing CFileItems
1964 VECFILEITEMS sortedFileItems;
1965 sortedFileItems.reserve(Size());
1966 for (SortItems::const_iterator it = sortItems.begin(); it != sortItems.end(); it++)
1968 CFileItemPtr item = m_items[(int)(*it)->at(FieldId).asInteger()];
1969 // Set the sort label in the CFileItem
1970 item->SetSortLabel(CStdStringW((*it)->at(FieldSort).asWideString()));
1972 sortedFileItems.push_back(item);
1975 // replace the current list with the re-ordered one
1976 m_items.assign(sortedFileItems.begin(), sortedFileItems.end());
1979 void CFileItemList::Randomize()
1981 CSingleLock lock(m_lock);
1982 random_shuffle(m_items.begin(), m_items.end());
1985 void CFileItemList::Archive(CArchive& ar)
1987 CSingleLock lock(m_lock);
1990 CFileItem::Archive(ar);
1993 if (m_items.size() > 0 && m_items[0]->IsParentFolder())
1996 ar << (int)(m_items.size() - i);
2000 ar << (int)m_sortDescription.sortBy;
2001 ar << (int)m_sortDescription.sortOrder;
2002 ar << (int)m_sortDescription.sortAttributes;
2003 ar << m_sortIgnoreFolders;
2004 ar << (int)m_cacheToDisc;
2006 ar << (int)m_sortDetails.size();
2007 for (unsigned int j = 0; j < m_sortDetails.size(); ++j)
2009 const SORT_METHOD_DETAILS &details = m_sortDetails[j];
2010 ar << (int)details.m_sortDescription.sortBy;
2011 ar << (int)details.m_sortDescription.sortOrder;
2012 ar << (int)details.m_sortDescription.sortAttributes;
2013 ar << details.m_buttonLabel;
2014 ar << details.m_labelMasks.m_strLabelFile;
2015 ar << details.m_labelMasks.m_strLabelFolder;
2016 ar << details.m_labelMasks.m_strLabel2File;
2017 ar << details.m_labelMasks.m_strLabel2Folder;
2022 for (; i < (int)m_items.size(); ++i)
2024 CFileItemPtr pItem = m_items[i];
2030 CFileItemPtr pParent;
2033 CFileItemPtr pItem=m_items[0];
2034 if (pItem->IsParentFolder())
2035 pParent.reset(new CFileItem(*pItem));
2038 SetFastLookup(false);
2042 CFileItem::Archive(ar);
2051 m_items.reserve(iSize + 1);
2052 m_items.push_back(pParent);
2055 m_items.reserve(iSize);
2057 bool fastLookup=false;
2061 ar >> (int&)tempint;
2062 m_sortDescription.sortBy = (SortBy)tempint;
2063 ar >> (int&)tempint;
2064 m_sortDescription.sortOrder = (SortOrder)tempint;
2065 ar >> (int&)tempint;
2066 m_sortDescription.sortAttributes = (SortAttribute)tempint;
2067 ar >> m_sortIgnoreFolders;
2068 ar >> (int&)tempint;
2069 m_cacheToDisc = CACHE_TYPE(tempint);
2071 unsigned int detailSize = 0;
2073 for (unsigned int j = 0; j < detailSize; ++j)
2075 SORT_METHOD_DETAILS details;
2076 ar >> (int&)tempint;
2077 details.m_sortDescription.sortBy = (SortBy)tempint;
2078 ar >> (int&)tempint;
2079 details.m_sortDescription.sortOrder = (SortOrder)tempint;
2080 ar >> (int&)tempint;
2081 details.m_sortDescription.sortAttributes = (SortAttribute)tempint;
2082 ar >> details.m_buttonLabel;
2083 ar >> details.m_labelMasks.m_strLabelFile;
2084 ar >> details.m_labelMasks.m_strLabelFolder;
2085 ar >> details.m_labelMasks.m_strLabel2File;
2086 ar >> details.m_labelMasks.m_strLabel2Folder;
2087 m_sortDetails.push_back(details);
2092 for (int i = 0; i < iSize; ++i)
2094 CFileItemPtr pItem(new CFileItem);
2099 SetFastLookup(fastLookup);
2103 void CFileItemList::FillInDefaultIcons()
2105 CSingleLock lock(m_lock);
2106 for (int i = 0; i < (int)m_items.size(); ++i)
2108 CFileItemPtr pItem = m_items[i];
2109 pItem->FillInDefaultIcon();
2113 int CFileItemList::GetFolderCount() const
2115 CSingleLock lock(m_lock);
2116 int nFolderCount = 0;
2117 for (int i = 0; i < (int)m_items.size(); i++)
2119 CFileItemPtr pItem = m_items[i];
2120 if (pItem->m_bIsFolder)
2124 return nFolderCount;
2127 int CFileItemList::GetObjectCount() const
2129 CSingleLock lock(m_lock);
2131 int numObjects = (int)m_items.size();
2132 if (numObjects && m_items[0]->IsParentFolder())
2138 int CFileItemList::GetFileCount() const
2140 CSingleLock lock(m_lock);
2142 for (int i = 0; i < (int)m_items.size(); i++)
2144 CFileItemPtr pItem = m_items[i];
2145 if (!pItem->m_bIsFolder)
2152 int CFileItemList::GetSelectedCount() const
2154 CSingleLock lock(m_lock);
2156 for (int i = 0; i < (int)m_items.size(); i++)
2158 CFileItemPtr pItem = m_items[i];
2159 if (pItem->IsSelected())
2166 void CFileItemList::FilterCueItems()
2168 CSingleLock lock(m_lock);
2169 // Handle .CUE sheet files...
2170 VECSONGS itemstoadd;
2171 CStdStringArray itemstodelete;
2172 for (int i = 0; i < (int)m_items.size(); i++)
2174 CFileItemPtr pItem = m_items[i];
2175 if (!pItem->m_bIsFolder)
2176 { // see if it's a .CUE sheet
2177 if (pItem->IsCUESheet())
2179 CCueDocument cuesheet;
2180 if (cuesheet.Parse(pItem->GetPath()))
2183 cuesheet.GetSongs(newitems);
2185 std::vector<CStdString> MediaFileVec;
2186 cuesheet.GetMediaFiles(MediaFileVec);
2188 // queue the cue sheet and the underlying media file for deletion
2189 for(std::vector<CStdString>::iterator itMedia = MediaFileVec.begin(); itMedia != MediaFileVec.end(); itMedia++)
2191 CStdString strMediaFile = *itMedia;
2192 CStdString fileFromCue = strMediaFile; // save the file from the cue we're matching against,
2193 // as we're going to search for others here...
2194 bool bFoundMediaFile = CFile::Exists(strMediaFile);
2195 // queue the cue sheet and the underlying media file for deletion
2196 if (!bFoundMediaFile)
2198 // try file in same dir, not matching case...
2199 if (Contains(strMediaFile))
2201 bFoundMediaFile = true;
2205 // try removing the .cue extension...
2206 strMediaFile = pItem->GetPath();
2207 URIUtils::RemoveExtension(strMediaFile);
2208 CFileItem item(strMediaFile, false);
2209 if (item.IsAudio() && Contains(strMediaFile))
2211 bFoundMediaFile = true;
2214 { // try replacing the extension with one of our allowed ones.
2215 CStdStringArray extensions;
2216 StringUtils::SplitString(g_advancedSettings.m_musicExtensions, "|", extensions);
2217 for (unsigned int i = 0; i < extensions.size(); i++)
2219 strMediaFile = URIUtils::ReplaceExtension(pItem->GetPath(), extensions[i]);
2220 CFileItem item(strMediaFile, false);
2221 if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile))
2223 bFoundMediaFile = true;
2230 if (bFoundMediaFile)
2232 itemstodelete.push_back(pItem->GetPath());
2233 itemstodelete.push_back(strMediaFile);
2234 // get the additional stuff (year, genre etc.) from the underlying media files tag.
2236 auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(strMediaFile));
2237 if (NULL != pLoader.get())
2240 pLoader->Load(strMediaFile, tag);
2242 // fill in any missing entries from underlying media file
2243 for (int j = 0; j < (int)newitems.size(); j++)
2245 CSong song = newitems[j];
2246 // only for songs that actually match the current media file
2247 if (song.strFileName == fileFromCue)
2249 // we might have a new media file from the above matching code
2250 song.strFileName = strMediaFile;
2253 if (song.strAlbum.empty() && !tag.GetAlbum().empty()) song.strAlbum = tag.GetAlbum();
2254 if (song.albumArtist.empty() && !tag.GetAlbumArtist().empty()) song.albumArtist = tag.GetAlbumArtist();
2255 if (song.genre.empty() && !tag.GetGenre().empty()) song.genre = tag.GetGenre();
2256 if (song.artist.empty() && !tag.GetArtist().empty()) song.artist = tag.GetArtist();
2257 if (tag.GetDiscNumber()) song.iTrack |= (tag.GetDiscNumber() << 16); // see CMusicInfoTag::GetDiscNumber()
2258 SYSTEMTIME dateTime;
2259 tag.GetReleaseDate(dateTime);
2260 if (dateTime.wYear) song.iYear = dateTime.wYear;
2261 if (song.embeddedArt.empty() && !tag.GetCoverArtInfo().empty())
2262 song.embeddedArt = tag.GetCoverArtInfo();
2264 if (!song.iDuration && tag.GetDuration() > 0)
2265 { // must be the last song
2266 song.iDuration = (tag.GetDuration() * 75 - song.iStartOffset + 37) / 75;
2268 // add this item to the list
2269 itemstoadd.push_back(song);
2274 { // remove the .cue sheet from the directory
2275 itemstodelete.push_back(pItem->GetPath());
2280 { // remove the .cue sheet from the directory (can't parse it - no point listing it)
2281 itemstodelete.push_back(pItem->GetPath());
2286 // now delete the .CUE files and underlying media files.
2287 for (int i = 0; i < (int)itemstodelete.size(); i++)
2289 for (int j = 0; j < (int)m_items.size(); j++)
2291 CFileItemPtr pItem = m_items[j];
2292 if (stricmp(pItem->GetPath().c_str(), itemstodelete[i].c_str()) == 0)
2293 { // delete this item
2294 m_items.erase(m_items.begin() + j);
2299 // and add the files from the .CUE sheet
2300 for (int i = 0; i < (int)itemstoadd.size(); i++)
2302 // now create the file item, and add to the item list.
2303 CFileItemPtr pItem(new CFileItem(itemstoadd[i]));
2304 m_items.push_back(pItem);
2308 // Remove the extensions from the filenames
2309 void CFileItemList::RemoveExtensions()
2311 CSingleLock lock(m_lock);
2312 for (int i = 0; i < Size(); ++i)
2313 m_items[i]->RemoveExtension();
2316 void CFileItemList::Stack(bool stackFiles /* = true */)
2318 CSingleLock lock(m_lock);
2321 if (IsVirtualDirectoryRoot() || IsLiveTV() || IsSourcesPath())
2324 SetProperty("isstacked", true);
2326 // items needs to be sorted for stuff below to work properly
2327 Sort(SortByLabel, SortOrderAscending);
2335 void CFileItemList::StackFolders()
2337 // Precompile our REs
2338 VECCREGEXP folderRegExps;
2339 CRegExp folderRegExp(true, CRegExp::autoUtf8);
2340 const CStdStringArray& strFolderRegExps = g_advancedSettings.m_folderStackRegExps;
2342 CStdStringArray::const_iterator strExpression = strFolderRegExps.begin();
2343 while (strExpression != strFolderRegExps.end())
2345 if (!folderRegExp.RegComp(*strExpression))
2346 CLog::Log(LOGERROR, "%s: Invalid folder stack RegExp:'%s'", __FUNCTION__, strExpression->c_str());
2348 folderRegExps.push_back(folderRegExp);
2354 for (int i = 0; i < Size(); i++)
2356 CFileItemPtr item = Get(i);
2357 // combined the folder checks
2358 if (item->m_bIsFolder)
2360 // only check known fast sources?
2362 // 1. rars and zips may be on slow sources? is this supposed to be allowed?
2363 if( !item->IsRemote()
2367 || URIUtils::IsInRAR(item->GetPath())
2368 || URIUtils::IsInZIP(item->GetPath())
2369 || URIUtils::IsOnLAN(item->GetPath())
2372 // stack cd# folders if contains only a single video file
2376 VECCREGEXP::iterator expr = folderRegExps.begin();
2377 while (!bMatch && expr != folderRegExps.end())
2379 //CLog::Log(LOGDEBUG,"%s: Running expression %s on %s", __FUNCTION__, expr->GetPattern().c_str(), item->GetLabel().c_str());
2380 bMatch = (expr->RegFind(item->GetLabel().c_str()) != -1);
2383 CFileItemList items;
2384 CDirectory::GetDirectory(item->GetPath(),items,g_advancedSettings.m_videoExtensions);
2385 // optimized to only traverse listing once by checking for filecount
2386 // and recording last file item for later use
2389 for (int j = 0; j < items.Size(); j++)
2391 if (!items[j]->m_bIsFolder)
2402 *item = *items[index];
2407 // check for dvd folders
2410 std::string dvdPath = item->GetOpticalMediaPath();
2412 if (!dvdPath.empty())
2414 // NOTE: should this be done for the CD# folders too?
2415 item->m_bIsFolder = false;
2416 item->SetPath(dvdPath);
2417 item->SetLabel2("");
2418 item->SetLabelPreformated(true);
2419 m_sortDescription.sortBy = SortByNone; /* sorting is now broken */
2427 void CFileItemList::StackFiles()
2429 // Precompile our REs
2430 VECCREGEXP stackRegExps;
2431 CRegExp tmpRegExp(true, CRegExp::autoUtf8);
2432 const CStdStringArray& strStackRegExps = g_advancedSettings.m_videoStackRegExps;
2433 CStdStringArray::const_iterator strRegExp = strStackRegExps.begin();
2434 while (strRegExp != strStackRegExps.end())
2436 if (tmpRegExp.RegComp(*strRegExp))
2438 if (tmpRegExp.GetCaptureTotal() == 4)
2439 stackRegExps.push_back(tmpRegExp);
2441 CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have 4 captures.", strRegExp->c_str());
2446 // now stack the files, some of which may be from the previous stack iteration
2450 CFileItemPtr item1 = Get(i);
2452 // skip folders, nfo files, playlists
2453 if (item1->m_bIsFolder
2454 || item1->IsParentFolder()
2456 || item1->IsPlayList()
2466 CStdString stackName;
2468 CStdString filePath;
2470 VECCREGEXP::iterator expr = stackRegExps.begin();
2472 URIUtils::Split(item1->GetPath(), filePath, file1);
2473 if (URIUtils::ProtocolHasEncodedFilename(CURL(filePath).GetProtocol() ) )
2474 file1 = CURL::Decode(file1);
2477 while (expr != stackRegExps.end())
2479 if (expr->RegFind(file1, offset) != -1)
2481 CStdString Title1 = expr->GetMatch(1),
2482 Volume1 = expr->GetMatch(2),
2483 Ignore1 = expr->GetMatch(3),
2484 Extension1 = expr->GetMatch(4);
2486 Title1 = file1.substr(0, expr->GetSubStart(2));
2490 CFileItemPtr item2 = Get(j);
2492 // skip folders, nfo files, playlists
2493 if (item2->m_bIsFolder
2494 || item2->IsParentFolder()
2496 || item2->IsPlayList()
2504 CStdString file2, filePath2;
2505 URIUtils::Split(item2->GetPath(), filePath2, file2);
2506 if (URIUtils::ProtocolHasEncodedFilename(CURL(filePath2).GetProtocol() ) )
2507 file2 = CURL::Decode(file2);
2509 if (expr->RegFind(file2, offset) != -1)
2511 CStdString Title2 = expr->GetMatch(1),
2512 Volume2 = expr->GetMatch(2),
2513 Ignore2 = expr->GetMatch(3),
2514 Extension2 = expr->GetMatch(4);
2516 Title2 = file2.substr(0, expr->GetSubStart(2));
2517 if (Title1.Equals(Title2))
2519 if (!Volume1.Equals(Volume2))
2521 if (Ignore1.Equals(Ignore2) && Extension1.Equals(Extension2))
2523 if (stack.size() == 0)
2525 stackName = Title1 + Ignore1 + Extension1;
2527 size += item1->m_dwSize;
2530 size += item2->m_dwSize;
2539 else if (!Ignore1.Equals(Ignore2)) // False positive, try again with offset
2541 offset = expr->GetSubStart(3);
2544 else // Extension mismatch
2551 else // Title mismatch
2558 else // No match 2, next expression
2567 expr = stackRegExps.end();
2574 if (stack.size() > 1)
2576 // have a stack, remove the items and add the stacked item
2577 // dont actually stack a multipart rar set, just remove all items but the first
2578 CStdString stackPath;
2579 if (Get(stack[0])->IsRAR())
2580 stackPath = Get(stack[0])->GetPath();
2583 CStackDirectory dir;
2584 stackPath = dir.ConstructStackPath(*this, stack);
2586 item1->SetPath(stackPath);
2588 for (unsigned k = 1; k < stack.size(); k++)
2590 // item->m_bIsFolder = true; // don't treat stacked files as folders
2591 // the label may be in a different char set from the filename (eg over smb
2592 // the label is converted from utf8, but the filename is not)
2593 if (!CSettings::Get().GetBool("filelists.showextensions"))
2594 URIUtils::RemoveExtension(stackName);
2596 item1->SetLabel(stackName);
2597 item1->m_dwSize = size;
2605 bool CFileItemList::Load(int windowID)
2608 if (file.Open(GetDiscFileCache(windowID)))
2610 CArchive ar(&file, CArchive::load);
2612 CLog::Log(LOGDEBUG,"Loading items: %i, directory: %s sort method: %i, ascending: %s", Size(), CURL::GetRedacted(GetPath()).c_str(), m_sortDescription.sortBy,
2613 m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false");
2622 bool CFileItemList::Save(int windowID)
2628 CLog::Log(LOGDEBUG,"Saving fileitems [%s]", CURL::GetRedacted(GetPath()).c_str());
2631 if (file.OpenForWrite(GetDiscFileCache(windowID), true)) // overwrite always
2633 CArchive ar(&file, CArchive::store);
2635 CLog::Log(LOGDEBUG," -- items: %i, sort method: %i, ascending: %s", iSize, m_sortDescription.sortBy, m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false");
2644 void CFileItemList::RemoveDiscCache(int windowID) const
2646 CStdString cacheFile(GetDiscFileCache(windowID));
2647 if (CFile::Exists(cacheFile))
2649 CLog::Log(LOGDEBUG,"Clearing cached fileitems [%s]",GetPath().c_str());
2650 CFile::Delete(cacheFile);
2654 CStdString CFileItemList::GetDiscFileCache(int windowID) const
2656 CStdString strPath(GetPath());
2657 URIUtils::RemoveSlashAtEnd(strPath);
2660 crc.ComputeFromLowerCase(strPath);
2662 CStdString cacheFile;
2663 if (IsCDDA() || IsOnDVD())
2664 cacheFile = StringUtils::Format("special://temp/r-%08x.fi", (unsigned __int32)crc);
2665 else if (IsMusicDb())
2666 cacheFile = StringUtils::Format("special://temp/mdb-%08x.fi", (unsigned __int32)crc);
2667 else if (IsVideoDb())
2668 cacheFile = StringUtils::Format("special://temp/vdb-%08x.fi", (unsigned __int32)crc);
2669 else if (IsSmartPlayList())
2670 cacheFile = StringUtils::Format("special://temp/sp-%08x.fi", (unsigned __int32)crc);
2672 cacheFile = StringUtils::Format("special://temp/%i-%08x.fi", windowID, (unsigned __int32)crc);
2674 cacheFile = StringUtils::Format("special://temp/%08x.fi", (unsigned __int32)crc);
2678 bool CFileItemList::AlwaysCache() const
2680 // some database folders are always cached
2682 return CMusicDatabaseDirectory::CanCache(GetPath());
2684 return CVideoDatabaseDirectory::CanCache(GetPath());
2686 return true; // always cache
2690 CStdString CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */, bool fallbackToFolder /* = false */) const
2692 if (m_strPath.empty()
2693 || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://")
2694 || StringUtils::StartsWithNoCase(m_strPath, "newplaylist://")
2695 || m_bIsShareOrDrive
2696 || IsInternetStream()
2697 || URIUtils::IsUPnP(m_strPath)
2698 || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
2705 // we first check for <filename>.tbn or <foldername>.tbn
2706 CStdString fileThumb(GetTBNFile());
2707 if (CFile::Exists(fileThumb))
2710 // Fall back to folder thumb, if requested
2711 if (!m_bIsFolder && fallbackToFolder)
2713 CFileItem item(URIUtils::GetDirectory(m_strPath), true);
2714 return item.GetUserMusicThumb(alwaysCheckRemote);
2717 // if a folder, check for folder.jpg
2718 if (m_bIsFolder && !IsFileFolder() && (!IsRemote() || alwaysCheckRemote || CSettings::Get().GetBool("musicfiles.findremotethumbs")))
2720 CStdStringArray thumbs;
2721 StringUtils::SplitString(g_advancedSettings.m_musicThumbs, "|", thumbs);
2722 for (unsigned int i = 0; i < thumbs.size(); ++i)
2724 CStdString folderThumb(GetFolderThumb(thumbs[i]));
2725 if (CFile::Exists(folderThumb))
2735 // Gets the .tbn filename from a file or folder name.
2736 // <filename>.ext -> <filename>.tbn
2737 // <foldername>/ -> <foldername>.tbn
2738 CStdString CFileItem::GetTBNFile() const
2740 CStdString thumbFile;
2741 CStdString strFile = m_strPath;
2745 CStdString strPath, strReturn;
2746 URIUtils::GetParentPath(m_strPath,strPath);
2747 CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2748 CStdString strTBNFile = item.GetTBNFile();
2749 strReturn = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strTBNFile));
2750 if (CFile::Exists(strReturn))
2753 strFile = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)));
2756 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2758 CStdString strPath = URIUtils::GetDirectory(strFile);
2759 CStdString strParent;
2760 URIUtils::GetParentPath(strPath,strParent);
2761 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(m_strPath));
2765 strFile = url.GetFileName();
2767 if (m_bIsFolder && !IsFileFolder())
2768 URIUtils::RemoveSlashAtEnd(strFile);
2770 if (!strFile.empty())
2772 if (m_bIsFolder && !IsFileFolder())
2773 thumbFile = strFile + ".tbn"; // folder, so just add ".tbn"
2775 thumbFile = URIUtils::ReplaceExtension(strFile, ".tbn");
2776 url.SetFileName(thumbFile);
2777 thumbFile = url.Get();
2782 bool CFileItem::SkipLocalArt() const
2784 return (m_strPath.empty()
2785 || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://")
2786 || StringUtils::StartsWithNoCase(m_strPath, "newplaylist://")
2787 || m_bIsShareOrDrive
2788 || IsInternetStream()
2789 || URIUtils::IsUPnP(m_strPath)
2790 || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
2798 CStdString CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) const
2806 thumb = GetLocalArt(artFile, false);
2807 if (!thumb.empty() && CFile::Exists(thumb))
2810 if ((useFolder || (m_bIsFolder && !IsFileFolder())) && !artFile.empty())
2812 CStdString thumb2 = GetLocalArt(artFile, true);
2813 if (!thumb2.empty() && thumb2 != thumb && CFile::Exists(thumb2))
2819 CStdString CFileItem::GetLocalArt(const std::string &artFile, bool useFolder) const
2821 // no retrieving of empty art files from folders
2822 if (useFolder && artFile.empty())
2825 CStdString strFile = m_strPath;
2828 /* CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2829 CStdString localArt = item.GetLocalArt(artFile);
2833 URIUtils::GetParentPath(m_strPath,strPath);
2834 strFile = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)));
2837 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2839 CStdString strPath = URIUtils::GetDirectory(strFile);
2840 CStdString strParent;
2841 URIUtils::GetParentPath(strPath,strParent);
2842 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(strFile));
2846 strFile = CMultiPathDirectory::GetFirstPath(m_strPath);
2848 if (IsOpticalMediaFile())
2849 { // optical media files should be treated like folders
2851 strFile = GetLocalMetadataPath();
2853 else if (useFolder && !(m_bIsFolder && !IsFileFolder()))
2854 strFile = URIUtils::GetDirectory(strFile);
2856 if (strFile.empty()) // empty filepath -> nothing to find
2861 if (!artFile.empty())
2862 return URIUtils::AddFileToFolder(strFile, artFile);
2866 if (artFile.empty()) // old thumbnail matching
2867 return URIUtils::ReplaceExtension(strFile, ".tbn");
2869 return URIUtils::ReplaceExtension(strFile, "-" + artFile);
2874 CStdString CFileItem::GetFolderThumb(const CStdString &folderJPG /* = "folder.jpg" */) const
2876 CStdString strFolder = m_strPath;
2879 URIUtils::IsInRAR(strFolder) ||
2880 URIUtils::IsInZIP(strFolder))
2882 URIUtils::GetParentPath(m_strPath,strFolder);
2886 strFolder = CMultiPathDirectory::GetFirstPath(m_strPath);
2888 return URIUtils::AddFileToFolder(strFolder, folderJPG);
2891 CStdString CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const
2893 if (IsLabelPreformated())
2896 if (m_pvrRecordingInfoTag)
2897 return m_pvrRecordingInfoTag->m_strTitle;
2898 else if (CUtil::IsTVRecording(m_strPath))
2900 CStdString title = CPVRRecording::GetTitleFromURL(m_strPath);
2905 CStdString strMovieName = GetBaseMoviePath(bUseFolderNames);
2907 if (URIUtils::IsStack(strMovieName))
2908 strMovieName = CStackDirectory::GetStackedTitlePath(strMovieName);
2910 URIUtils::RemoveSlashAtEnd(strMovieName);
2912 return CURL::Decode(URIUtils::GetFileName(strMovieName));
2915 CStdString CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
2917 CStdString strMovieName = m_strPath;
2920 strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
2922 if (IsOpticalMediaFile())
2923 return GetLocalMetadataPath();
2925 if ((!m_bIsFolder || URIUtils::IsInArchive(m_strPath)) && bUseFolderNames)
2927 CStdString name2(strMovieName);
2928 URIUtils::GetParentPath(name2,strMovieName);
2929 if (URIUtils::IsInArchive(m_strPath))
2931 CStdString strArchivePath;
2932 URIUtils::GetParentPath(strMovieName, strArchivePath);
2933 strMovieName = strArchivePath;
2937 return strMovieName;
2940 CStdString CFileItem::GetLocalFanart() const
2944 if (!HasVideoInfoTag())
2945 return ""; // nothing can be done
2946 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
2947 return dbItem.GetLocalFanart();
2950 CStdString strFile2;
2951 CStdString strFile = m_strPath;
2955 URIUtils::GetParentPath(m_strPath,strPath);
2956 CStackDirectory dir;
2957 CStdString strPath2;
2958 strPath2 = dir.GetStackedTitlePath(strFile);
2959 strFile = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strPath2));
2960 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
2961 CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-fanart"));
2962 strFile2 = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strTBNFile));
2964 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2966 CStdString strPath = URIUtils::GetDirectory(strFile);
2967 CStdString strParent;
2968 URIUtils::GetParentPath(strPath,strParent);
2969 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(m_strPath));
2972 // no local fanart available for these
2973 if (IsInternetStream()
2974 || URIUtils::IsUPnP(strFile)
2975 || URIUtils::IsBluray(strFile)
2980 || (URIUtils::IsFTP(strFile) && !g_advancedSettings.m_bFTPThumbs)
2981 || m_strPath.empty())
2984 CStdString strDir = URIUtils::GetDirectory(strFile);
2989 CFileItemList items;
2990 CDirectory::GetDirectory(strDir, items, g_advancedSettings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
2991 if (IsOpticalMediaFile())
2992 { // grab from the optical media parent folder as well
2993 CFileItemList moreItems;
2994 CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems, g_advancedSettings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
2995 items.Append(moreItems);
2998 CStdStringArray fanarts;
2999 StringUtils::SplitString(g_advancedSettings.m_fanartImages, "|", fanarts);
3001 strFile = URIUtils::ReplaceExtension(strFile, "-fanart");
3002 fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile));
3004 if (!strFile2.empty())
3005 fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile2));
3007 for (unsigned int i = 0; i < fanarts.size(); ++i)
3009 for (int j = 0; j < items.Size(); j++)
3011 CStdString strCandidate = URIUtils::GetFileName(items[j]->m_strPath);
3012 URIUtils::RemoveExtension(strCandidate);
3013 CStdString strFanart = fanarts[i];
3014 URIUtils::RemoveExtension(strFanart);
3015 if (StringUtils::EqualsNoCase(strCandidate, strFanart))
3016 return items[j]->m_strPath;
3023 CStdString CFileItem::GetLocalMetadataPath() const
3025 if (m_bIsFolder && !IsFileFolder())
3028 CStdString parent(URIUtils::GetParentPath(m_strPath));
3029 CStdString parentFolder(parent);
3030 URIUtils::RemoveSlashAtEnd(parentFolder);
3031 parentFolder = URIUtils::GetFileName(parentFolder);
3032 if (StringUtils::EqualsNoCase(parentFolder, "VIDEO_TS") || StringUtils::EqualsNoCase(parentFolder, "BDMV"))
3033 { // go back up another one
3034 parent = URIUtils::GetParentPath(parent);
3039 bool CFileItem::LoadMusicTag()
3045 if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
3048 CMusicDatabase musicDatabase;
3049 if (musicDatabase.Open())
3052 if (musicDatabase.GetSongByFileName(m_strPath, song))
3054 GetMusicInfoTag()->SetSong(song);
3055 SetArt("thumb", song.strThumb);
3058 musicDatabase.Close();
3060 // load tag from file
3061 CLog::Log(LOGDEBUG, "%s: loading tag information for file: %s", __FUNCTION__, m_strPath.c_str());
3062 CMusicInfoTagLoaderFactory factory;
3063 auto_ptr<IMusicInfoTagLoader> pLoader (factory.CreateLoader(m_strPath));
3064 if (NULL != pLoader.get())
3066 if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
3069 // no tag - try some other things
3072 // we have the tracknumber...
3073 int iTrack = GetMusicInfoTag()->GetTrackNumber();
3076 CStdString strText = g_localizeStrings.Get(554); // "Track"
3077 if (!strText.empty() && strText[strText.size() - 1] != ' ')
3079 CStdString strTrack = StringUtils::Format(strText + "%i", iTrack);
3080 GetMusicInfoTag()->SetTitle(strTrack);
3081 GetMusicInfoTag()->SetLoaded(true);
3087 CStdString fileName = URIUtils::GetFileName(m_strPath);
3088 URIUtils::RemoveExtension(fileName);
3089 for (unsigned int i = 0; i < g_advancedSettings.m_musicTagsFromFileFilters.size(); i++)
3091 CLabelFormatter formatter(g_advancedSettings.m_musicTagsFromFileFilters[i], "");
3092 if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
3094 GetMusicInfoTag()->SetLoaded(true);
3102 void CFileItemList::Swap(unsigned int item1, unsigned int item2)
3104 if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size())
3105 std::swap(m_items[item1], m_items[item2]);
3108 bool CFileItemList::UpdateItem(const CFileItem *item)
3110 if (!item) return false;
3112 CSingleLock lock(m_lock);
3113 for (unsigned int i = 0; i < m_items.size(); i++)
3115 CFileItemPtr pItem = m_items[i];
3116 if (pItem->IsSamePath(item))
3118 pItem->UpdateInfo(*item);
3125 void CFileItemList::AddSortMethod(SortBy sortBy, int buttonLabel, const LABEL_MASKS &labelMasks, SortAttribute sortAttributes /* = SortAttributeNone */)
3127 AddSortMethod(sortBy, sortAttributes, buttonLabel, labelMasks);
3130 void CFileItemList::AddSortMethod(SortBy sortBy, SortAttribute sortAttributes, int buttonLabel, const LABEL_MASKS &labelMasks)
3132 SortDescription sorting;
3133 sorting.sortBy = sortBy;
3134 sorting.sortAttributes = sortAttributes;
3136 AddSortMethod(sorting, buttonLabel, labelMasks);
3139 void CFileItemList::AddSortMethod(SortDescription sortDescription, int buttonLabel, const LABEL_MASKS &labelMasks)
3141 SORT_METHOD_DETAILS sort;
3142 sort.m_sortDescription = sortDescription;
3143 sort.m_buttonLabel = buttonLabel;
3144 sort.m_labelMasks = labelMasks;
3146 m_sortDetails.push_back(sort);
3149 void CFileItemList::SetReplaceListing(bool replace)
3151 m_replaceListing = replace;
3154 void CFileItemList::ClearSortState()
3156 m_sortDescription.sortBy = SortByNone;
3157 m_sortDescription.sortOrder = SortOrderNone;
3158 m_sortDescription.sortAttributes = SortAttributeNone;
3161 CVideoInfoTag* CFileItem::GetVideoInfoTag()
3163 if (!m_videoInfoTag)
3164 m_videoInfoTag = new CVideoInfoTag;
3166 return m_videoInfoTag;
3169 CEpgInfoTag* CFileItem::GetEPGInfoTag()
3172 m_epgInfoTag = new CEpgInfoTag;
3174 return m_epgInfoTag;
3177 CPVRChannel* CFileItem::GetPVRChannelInfoTag()
3179 if (!m_pvrChannelInfoTag)
3180 m_pvrChannelInfoTag = new CPVRChannel;
3182 return m_pvrChannelInfoTag;
3185 CPVRRecording* CFileItem::GetPVRRecordingInfoTag()
3187 if (!m_pvrRecordingInfoTag)
3188 m_pvrRecordingInfoTag = new CPVRRecording;
3190 return m_pvrRecordingInfoTag;
3193 CPVRTimerInfoTag* CFileItem::GetPVRTimerInfoTag()
3195 if (!m_pvrTimerInfoTag)
3196 m_pvrTimerInfoTag = new CPVRTimerInfoTag;
3198 return m_pvrTimerInfoTag;
3201 CPictureInfoTag* CFileItem::GetPictureInfoTag()
3203 if (!m_pictureInfoTag)
3204 m_pictureInfoTag = new CPictureInfoTag;
3206 return m_pictureInfoTag;
3209 MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
3211 if (!m_musicInfoTag)
3212 m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
3214 return m_musicInfoTag;
3217 CStdString CFileItem::FindTrailer() const
3219 CStdString strFile2;
3220 CStdString strFile = m_strPath;
3224 URIUtils::GetParentPath(m_strPath,strPath);
3225 CStackDirectory dir;
3226 CStdString strPath2;
3227 strPath2 = dir.GetStackedTitlePath(strFile);
3228 strFile = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2));
3229 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
3230 CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-trailer"));
3231 strFile2 = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile));
3233 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
3235 CStdString strPath = URIUtils::GetDirectory(strFile);
3236 CStdString strParent;
3237 URIUtils::GetParentPath(strPath,strParent);
3238 strFile = URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath));
3241 // no local trailer available for these
3242 if (IsInternetStream()
3243 || URIUtils::IsUPnP(strFile)
3244 || URIUtils::IsBluray(strFile)
3250 CStdString strDir = URIUtils::GetDirectory(strFile);
3251 CFileItemList items;
3252 CDirectory::GetDirectory(strDir, items, g_advancedSettings.m_videoExtensions, DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO | DIR_FLAG_NO_FILE_DIRS);
3253 URIUtils::RemoveExtension(strFile);
3254 strFile += "-trailer";
3255 CStdString strFile3 = URIUtils::AddFileToFolder(strDir, "movie-trailer");
3257 // Precompile our REs
3258 VECCREGEXP matchRegExps;
3259 CRegExp tmpRegExp(true, CRegExp::autoUtf8);
3260 const CStdStringArray& strMatchRegExps = g_advancedSettings.m_trailerMatchRegExps;
3262 CStdStringArray::const_iterator strRegExp = strMatchRegExps.begin();
3263 while (strRegExp != strMatchRegExps.end())
3265 if (tmpRegExp.RegComp(*strRegExp))
3267 matchRegExps.push_back(tmpRegExp);
3272 CStdString strTrailer;
3273 for (int i = 0; i < items.Size(); i++)
3275 CStdString strCandidate = items[i]->m_strPath;
3276 URIUtils::RemoveExtension(strCandidate);
3277 if (StringUtils::EqualsNoCase(strCandidate, strFile) ||
3278 StringUtils::EqualsNoCase(strCandidate, strFile2) ||
3279 StringUtils::EqualsNoCase(strCandidate, strFile3))
3281 strTrailer = items[i]->m_strPath;
3286 VECCREGEXP::iterator expr = matchRegExps.begin();
3288 while (expr != matchRegExps.end())
3290 if (expr->RegFind(strCandidate) != -1)
3292 strTrailer = items[i]->m_strPath;
3304 int CFileItem::GetVideoContentType() const
3306 VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
3307 if (HasVideoInfoTag() && !GetVideoInfoTag()->m_strShowTitle.empty()) // tvshow
3308 type = VIDEODB_CONTENT_TVSHOWS;
3309 if (HasVideoInfoTag() && GetVideoInfoTag()->m_iSeason > -1 && !m_bIsFolder) // episode
3310 return VIDEODB_CONTENT_EPISODES;
3311 if (HasVideoInfoTag() && !GetVideoInfoTag()->m_artist.empty()) // music video
3312 return VIDEODB_CONTENT_MUSICVIDEOS;
3314 CVideoDatabaseDirectory dir;
3315 VIDEODATABASEDIRECTORY::CQueryParams params;
3316 dir.GetQueryParams(m_strPath, params);
3317 if (params.GetSetId() != -1 && params.GetMovieId() == -1) // movie set
3318 return VIDEODB_CONTENT_MOVIE_SETS;