2 * Copyright (C) 2005-2012 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 "music/tags/MusicInfoTagLoaderFactory.h"
35 #include "CueDocument.h"
36 #include "video/VideoDatabase.h"
37 #include "music/MusicDatabase.h"
38 #include "utils/TuxBoxUtil.h"
40 #include "pvr/channels/PVRChannel.h"
41 #include "pvr/recordings/PVRRecording.h"
42 #include "pvr/timers/PVRTimerInfoTag.h"
43 #include "utils/Observer.h"
44 #include "video/VideoInfoTag.h"
45 #include "threads/SingleLock.h"
46 #include "music/tags/MusicInfoTag.h"
47 #include "pictures/PictureInfoTag.h"
48 #include "music/Artist.h"
49 #include "music/Album.h"
50 #include "music/Song.h"
52 #include "settings/GUISettings.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"
62 using namespace XFILE;
63 using namespace PLAYLIST;
64 using namespace MUSIC_INFO;
68 CFileItem::CFileItem(const CSong& song)
70 m_musicInfoTag = NULL;
71 m_videoInfoTag = NULL;
73 m_pvrChannelInfoTag = NULL;
74 m_pvrRecordingInfoTag = NULL;
75 m_pvrTimerInfoTag = NULL;
76 m_pictureInfoTag = NULL;
82 CFileItem::CFileItem(const CStdString &path, const CAlbum& album)
84 m_musicInfoTag = NULL;
85 m_videoInfoTag = NULL;
87 m_pvrChannelInfoTag = NULL;
88 m_pvrRecordingInfoTag = NULL;
89 m_pvrTimerInfoTag = NULL;
90 m_pictureInfoTag = NULL;
94 URIUtils::AddSlashAtEnd(m_strPath);
98 CFileItem::CFileItem(const CMusicInfoTag& music)
100 m_musicInfoTag = NULL;
101 m_videoInfoTag = NULL;
103 m_pvrChannelInfoTag = NULL;
104 m_pvrRecordingInfoTag = NULL;
105 m_pvrTimerInfoTag = NULL;
106 m_pictureInfoTag = NULL;
108 SetLabel(music.GetTitle());
109 m_strPath = music.GetURL();
110 m_bIsFolder = URIUtils::HasSlashAtEnd(m_strPath);
111 *GetMusicInfoTag() = music;
115 CFileItem::CFileItem(const CVideoInfoTag& movie)
117 m_musicInfoTag = NULL;
118 m_videoInfoTag = NULL;
120 m_pvrChannelInfoTag = NULL;
121 m_pvrRecordingInfoTag = NULL;
122 m_pvrTimerInfoTag = NULL;
123 m_pictureInfoTag = NULL;
126 SetFromVideoInfoTag(movie);
129 CFileItem::CFileItem(const CEpgInfoTag& tag)
131 m_musicInfoTag = NULL;
132 m_videoInfoTag = NULL;
134 m_pvrChannelInfoTag = NULL;
135 m_pvrRecordingInfoTag = NULL;
136 m_pvrTimerInfoTag = NULL;
137 m_pictureInfoTag = NULL;
141 m_strPath = tag.Path();
143 *GetEPGInfoTag() = tag;
144 SetLabel(tag.Title());
145 m_strLabel2 = tag.Plot();
146 m_dateTime = tag.StartAsLocalTime();
148 if (!tag.Icon().IsEmpty())
149 SetIconImage(tag.Icon());
152 CFileItem::CFileItem(const CPVRChannel& channel)
154 m_musicInfoTag = NULL;
155 m_videoInfoTag = NULL;
157 m_pvrChannelInfoTag = NULL;
158 m_pvrRecordingInfoTag = NULL;
159 m_pvrTimerInfoTag = NULL;
160 m_pictureInfoTag = NULL;
164 bool bHasEpgNow = channel.GetEPGNow(epgNow);
166 m_strPath = channel.Path();
168 *GetPVRChannelInfoTag() = channel;
169 SetLabel(channel.ChannelName());
170 m_strLabel2 = bHasEpgNow ? epgNow.Title() :
171 g_guiSettings.GetBool("epg.hidenoinfoavailable") ?
172 StringUtils::EmptyString :
173 g_localizeStrings.Get(19055); // no information available
175 if (channel.IsRadio())
177 CMusicInfoTag* musictag = GetMusicInfoTag();
180 musictag->SetURL(channel.Path());
181 musictag->SetTitle(m_strLabel2);
182 musictag->SetArtist(channel.ChannelName());
183 musictag->SetAlbumArtist(channel.ChannelName());
185 musictag->SetGenre(epgNow.Genre());
186 musictag->SetDuration(bHasEpgNow ? epgNow.GetDuration() : 3600);
187 musictag->SetLoaded(true);
188 musictag->SetComment("");
189 musictag->SetLyrics("");
193 if (!channel.IconPath().IsEmpty())
194 SetIconImage(channel.IconPath());
196 SetProperty("channelid", channel.ChannelID());
197 SetProperty("path", channel.Path());
198 SetArt("thumb", channel.IconPath());
201 CFileItem::CFileItem(const CPVRRecording& record)
203 m_musicInfoTag = NULL;
204 m_videoInfoTag = NULL;
206 m_pvrChannelInfoTag = NULL;
207 m_pvrRecordingInfoTag = NULL;
208 m_pvrTimerInfoTag = NULL;
209 m_pictureInfoTag = NULL;
213 m_strPath = record.m_strFileNameAndPath;
215 *GetPVRRecordingInfoTag() = record;
216 SetLabel(record.m_strTitle);
217 m_strLabel2 = record.m_strPlot;
220 CFileItem::CFileItem(const CPVRTimerInfoTag& timer)
222 m_musicInfoTag = NULL;
223 m_videoInfoTag = NULL;
225 m_pvrChannelInfoTag = NULL;
226 m_pvrRecordingInfoTag = NULL;
227 m_pvrTimerInfoTag = NULL;
228 m_pictureInfoTag = NULL;
232 m_strPath = timer.Path();
234 *GetPVRTimerInfoTag() = timer;
235 SetLabel(timer.Title());
236 m_strLabel2 = timer.Summary();
237 m_dateTime = timer.StartAsLocalTime();
239 if (!timer.ChannelIcon().IsEmpty())
240 SetIconImage(timer.ChannelIcon());
243 CFileItem::CFileItem(const CArtist& artist)
245 m_musicInfoTag = NULL;
246 m_videoInfoTag = NULL;
248 m_pvrChannelInfoTag = NULL;
249 m_pvrRecordingInfoTag = NULL;
250 m_pvrTimerInfoTag = NULL;
251 m_pictureInfoTag = NULL;
253 SetLabel(artist.strArtist);
254 m_strPath = artist.strArtist;
256 URIUtils::AddSlashAtEnd(m_strPath);
257 GetMusicInfoTag()->SetArtist(artist.strArtist);
260 CFileItem::CFileItem(const CGenre& genre)
262 m_musicInfoTag = NULL;
263 m_videoInfoTag = NULL;
265 m_pvrChannelInfoTag = NULL;
266 m_pvrRecordingInfoTag = NULL;
267 m_pvrTimerInfoTag = NULL;
268 m_pictureInfoTag = NULL;
270 SetLabel(genre.strGenre);
271 m_strPath = genre.strGenre;
273 URIUtils::AddSlashAtEnd(m_strPath);
274 GetMusicInfoTag()->SetGenre(genre.strGenre);
277 CFileItem::CFileItem(const CFileItem& item): CGUIListItem()
279 m_musicInfoTag = NULL;
280 m_videoInfoTag = NULL;
282 m_pvrChannelInfoTag = NULL;
283 m_pvrRecordingInfoTag = NULL;
284 m_pvrTimerInfoTag = NULL;
285 m_pictureInfoTag = NULL;
289 CFileItem::CFileItem(const CGUIListItem& item)
291 m_musicInfoTag = NULL;
292 m_videoInfoTag = NULL;
294 m_pvrChannelInfoTag = NULL;
295 m_pvrRecordingInfoTag = NULL;
296 m_pvrTimerInfoTag = NULL;
297 m_pictureInfoTag = NULL;
299 // not particularly pretty, but it gets around the issue of Reset() defaulting
300 // parameters in the CGUIListItem base class.
301 *((CGUIListItem *)this) = item;
304 CFileItem::CFileItem(void)
306 m_musicInfoTag = NULL;
307 m_videoInfoTag = NULL;
309 m_pvrChannelInfoTag = NULL;
310 m_pvrRecordingInfoTag = NULL;
311 m_pvrTimerInfoTag = NULL;
312 m_pictureInfoTag = NULL;
316 CFileItem::CFileItem(const CStdString& strLabel)
319 m_musicInfoTag = NULL;
320 m_videoInfoTag = NULL;
322 m_pvrChannelInfoTag = NULL;
323 m_pvrRecordingInfoTag = NULL;
324 m_pvrTimerInfoTag = NULL;
325 m_pictureInfoTag = NULL;
330 CFileItem::CFileItem(const CStdString& strPath, bool bIsFolder)
332 m_musicInfoTag = NULL;
333 m_videoInfoTag = NULL;
335 m_pvrChannelInfoTag = NULL;
336 m_pvrRecordingInfoTag = NULL;
337 m_pvrTimerInfoTag = NULL;
338 m_pictureInfoTag = NULL;
341 m_bIsFolder = bIsFolder;
342 // tuxbox urls cannot have a / at end
343 if (m_bIsFolder && !m_strPath.IsEmpty() && !IsFileFolder() && !URIUtils::IsTuxBox(m_strPath))
344 URIUtils::AddSlashAtEnd(m_strPath);
347 CFileItem::CFileItem(const CMediaSource& share)
349 m_musicInfoTag = NULL;
350 m_videoInfoTag = NULL;
352 m_pvrChannelInfoTag = NULL;
353 m_pvrRecordingInfoTag = NULL;
354 m_pvrTimerInfoTag = NULL;
355 m_pictureInfoTag = NULL;
358 m_bIsShareOrDrive = true;
359 m_strPath = share.strPath;
360 if (!IsRSS()) // no slash at end for rss feeds
361 URIUtils::AddSlashAtEnd(m_strPath);
362 CStdString label = share.strName;
363 if (!share.strStatus.IsEmpty())
364 label.Format("%s (%s)", share.strName.c_str(), share.strStatus.c_str());
366 m_iLockMode = share.m_iLockMode;
367 m_strLockCode = share.m_strLockCode;
368 m_iHasLock = share.m_iHasLock;
369 m_iBadPwdCount = share.m_iBadPwdCount;
370 m_iDriveType = share.m_iDriveType;
371 SetArt("thumb", share.m_strThumbnailImage);
372 SetLabelPreformated(true);
374 GetVideoInfoTag()->m_strFileNameAndPath = share.strDiskUniqueId; // share.strDiskUniqueId contains disc unique id
377 CFileItem::~CFileItem(void)
379 delete m_musicInfoTag;
380 delete m_videoInfoTag;
382 delete m_pvrChannelInfoTag;
383 delete m_pvrRecordingInfoTag;
384 delete m_pvrTimerInfoTag;
385 delete m_pictureInfoTag;
387 m_musicInfoTag = NULL;
388 m_videoInfoTag = NULL;
390 m_pvrChannelInfoTag = NULL;
391 m_pvrRecordingInfoTag = NULL;
392 m_pvrTimerInfoTag = NULL;
393 m_pictureInfoTag = NULL;
396 const CFileItem& CFileItem::operator=(const CFileItem& item)
398 if (this == &item) return * this;
399 CGUIListItem::operator=(item);
400 m_bLabelPreformated=item.m_bLabelPreformated;
402 m_strPath = item.GetPath();
403 m_bIsParentFolder = item.m_bIsParentFolder;
404 m_iDriveType = item.m_iDriveType;
405 m_bIsShareOrDrive = item.m_bIsShareOrDrive;
406 m_dateTime = item.m_dateTime;
407 m_dwSize = item.m_dwSize;
408 if (item.HasMusicInfoTag())
410 m_musicInfoTag = GetMusicInfoTag();
412 *m_musicInfoTag = *item.m_musicInfoTag;
416 delete m_musicInfoTag;
417 m_musicInfoTag = NULL;
420 if (item.HasVideoInfoTag())
422 m_videoInfoTag = GetVideoInfoTag();
424 *m_videoInfoTag = *item.m_videoInfoTag;
428 delete m_videoInfoTag;
429 m_videoInfoTag = NULL;
432 if (item.HasEPGInfoTag())
434 m_epgInfoTag = GetEPGInfoTag();
436 *m_epgInfoTag = *item.m_epgInfoTag;
446 if (item.HasPVRChannelInfoTag())
448 m_pvrChannelInfoTag = GetPVRChannelInfoTag();
449 if (m_pvrChannelInfoTag)
450 *m_pvrChannelInfoTag = *item.m_pvrChannelInfoTag;
454 if (m_pvrChannelInfoTag)
455 delete m_pvrChannelInfoTag;
457 m_pvrChannelInfoTag = NULL;
460 if (item.HasPVRRecordingInfoTag())
462 m_pvrRecordingInfoTag = GetPVRRecordingInfoTag();
463 if (m_pvrRecordingInfoTag)
464 *m_pvrRecordingInfoTag = *item.m_pvrRecordingInfoTag;
468 if (m_pvrRecordingInfoTag)
469 delete m_pvrRecordingInfoTag;
471 m_pvrRecordingInfoTag = NULL;
474 if (item.HasPVRTimerInfoTag())
476 m_pvrTimerInfoTag = GetPVRTimerInfoTag();
477 if (m_pvrTimerInfoTag)
478 *m_pvrTimerInfoTag = *item.m_pvrTimerInfoTag;
482 if (m_pvrTimerInfoTag)
483 delete m_pvrTimerInfoTag;
485 m_pvrTimerInfoTag = NULL;
488 if (item.HasPictureInfoTag())
490 m_pictureInfoTag = GetPictureInfoTag();
491 if (m_pictureInfoTag)
492 *m_pictureInfoTag = *item.m_pictureInfoTag;
496 delete m_pictureInfoTag;
497 m_pictureInfoTag = NULL;
500 m_lStartOffset = item.m_lStartOffset;
501 m_lStartPartNumber = item.m_lStartPartNumber;
502 m_lEndOffset = item.m_lEndOffset;
503 m_strDVDLabel = item.m_strDVDLabel;
504 m_strTitle = item.m_strTitle;
505 m_iprogramCount = item.m_iprogramCount;
506 m_idepth = item.m_idepth;
507 m_iLockMode = item.m_iLockMode;
508 m_strLockCode = item.m_strLockCode;
509 m_iHasLock = item.m_iHasLock;
510 m_iBadPwdCount = item.m_iBadPwdCount;
511 m_bCanQueue=item.m_bCanQueue;
512 m_mimetype = item.m_mimetype;
513 m_extrainfo = item.m_extrainfo;
514 m_specialSort = item.m_specialSort;
515 m_bIsAlbum = item.m_bIsAlbum;
519 void CFileItem::Reset()
523 m_bLabelPreformated=false;
525 m_overlayIcon = ICON_OVERLAY_NONE;
528 m_strDVDLabel.Empty();
533 m_bIsParentFolder=false;
534 m_bIsShareOrDrive = false;
536 m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
538 m_lStartPartNumber = 1;
542 m_iLockMode = LOCK_MODE_EVERYONE;
548 delete m_musicInfoTag;
550 delete m_videoInfoTag;
554 delete m_pvrChannelInfoTag;
555 m_pvrChannelInfoTag=NULL;
556 delete m_pvrRecordingInfoTag;
557 m_pvrRecordingInfoTag=NULL;
558 delete m_pvrTimerInfoTag;
559 m_pvrTimerInfoTag=NULL;
560 delete m_pictureInfoTag;
561 m_pictureInfoTag=NULL;
563 m_specialSort = SortSpecialNone;
568 void CFileItem::Archive(CArchive& ar)
570 CGUIListItem::Archive(ar);
574 ar << m_bIsParentFolder;
575 ar << m_bLabelPreformated;
577 ar << m_bIsShareOrDrive;
583 ar << m_iprogramCount;
585 ar << m_lStartOffset;
586 ar << m_lStartPartNumber;
590 ar << m_iBadPwdCount;
600 ar << *m_musicInfoTag;
607 ar << *m_videoInfoTag;
611 if (m_pictureInfoTag)
614 ar << *m_pictureInfoTag;
621 ar >> m_bIsParentFolder;
622 ar >> m_bLabelPreformated;
624 ar >> m_bIsShareOrDrive;
630 ar >> m_iprogramCount;
632 ar >> m_lStartOffset;
633 ar >> m_lStartPartNumber;
637 m_iLockMode = (LockType)temp;
639 ar >> m_iBadPwdCount;
645 m_specialSort = (SortSpecial)temp;
650 ar >> *GetMusicInfoTag();
653 ar >> *GetVideoInfoTag();
656 ar >> *GetPictureInfoTag();
662 void CFileItem::Serialize(CVariant& value) const
664 //CGUIListItem::Serialize(value["CGUIListItem"]);
666 value["strPath"] = m_strPath;
667 value["dateTime"] = (m_dateTime.IsValid()) ? m_dateTime.GetAsRFC1123DateTime() : "";
668 value["size"] = (int) m_dwSize / 1000;
669 value["DVDLabel"] = m_strDVDLabel;
670 value["title"] = m_strTitle;
671 value["mimetype"] = GetMimeType();
672 value["extrainfo"] = m_extrainfo;
675 (*m_musicInfoTag).Serialize(value["musicInfoTag"]);
678 (*m_videoInfoTag).Serialize(value["videoInfoTag"]);
680 if (m_pictureInfoTag)
681 (*m_pictureInfoTag).Serialize(value["pictureInfoTag"]);
684 void CFileItem::ToSortable(SortItem &sortable)
686 sortable[FieldPath] = m_strPath;
687 sortable[FieldDate] = (m_dateTime.IsValid()) ? m_dateTime.GetAsDBDateTime() : "";
688 sortable[FieldSize] = m_dwSize;
689 sortable[FieldDriveType] = m_iDriveType;
690 sortable[FieldStartOffset] = m_lStartOffset;
691 sortable[FieldEndOffset] = m_lEndOffset;
692 sortable[FieldProgramCount] = m_iprogramCount;
693 sortable[FieldBitrate] = m_dwSize;
694 sortable[FieldTitle] = m_strTitle;
695 sortable[FieldSortSpecial] = m_specialSort;
696 sortable[FieldFolder] = m_bIsFolder;
698 // If there's ever a need to convert more properties from CGUIListItem it might be
699 // worth to make CGUIListItem implement ISortable as well and call it from here
700 sortable[FieldLabel] = GetLabel();
702 if (HasMusicInfoTag())
703 GetMusicInfoTag()->ToSortable(sortable);
705 if (HasVideoInfoTag())
707 GetVideoInfoTag()->ToSortable(sortable);
709 if (GetVideoInfoTag()->m_type == "tvshow")
711 if (HasProperty("totalepisodes"))
712 sortable[FieldNumberOfEpisodes] = GetProperty("totalepisodes");
713 if (HasProperty("unwatchedepisodes"))
714 sortable[FieldNumberOfWatchedEpisodes] = GetProperty("unwatchedepisodes");
718 if (HasPictureInfoTag())
719 GetPictureInfoTag()->ToSortable(sortable);
721 if (HasPVRChannelInfoTag())
722 GetPVRChannelInfoTag()->ToSortable(sortable);
725 bool CFileItem::Exists(bool bUseCache /* = true */) const
727 if (m_strPath.IsEmpty()
728 || m_strPath.Equals("add")
729 || IsInternetStream()
731 || IsVirtualDirectoryRoot()
735 if (IsVideoDb() && HasVideoInfoTag())
737 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
738 return dbItem.Exists();
741 CStdString strPath = m_strPath;
743 if (URIUtils::IsMultiPath(strPath))
744 strPath = CMultiPathDirectory::GetFirstPath(strPath);
746 if (URIUtils::IsStack(strPath))
747 strPath = CStackDirectory::GetFirstStackedFile(strPath);
750 return CDirectory::Exists(strPath);
752 return CFile::Exists(strPath, bUseCache);
757 bool CFileItem::IsVideo() const
759 /* check preset mime type */
760 if( m_mimetype.Left(6).Equals("video/") )
763 if (HasVideoInfoTag()) return true;
764 if (HasMusicInfoTag()) return false;
765 if (HasPictureInfoTag()) return false;
766 if (IsPVRRecording()) return true;
768 if (IsHDHomeRun() || IsTuxBox() || URIUtils::IsDVD(m_strPath) || IsSlingbox())
771 CStdString extension;
772 if( m_mimetype.Left(12).Equals("application/") )
773 { /* check for some standard types */
774 extension = m_mimetype.Mid(12);
775 if( extension.Equals("ogg")
776 || extension.Equals("mp4")
777 || extension.Equals("mxf") )
781 URIUtils::GetExtension(m_strPath, extension);
783 if (extension.IsEmpty())
788 return (g_settings.m_videoExtensions.Find(extension) != -1);
791 bool CFileItem::IsEPG() const
793 if (HasEPGInfoTag()) return true; /// is this enough?
797 bool CFileItem::IsPVRChannel() const
799 if (HasPVRChannelInfoTag()) return true; /// is this enough?
803 bool CFileItem::IsPVRRecording() const
805 if (HasPVRRecordingInfoTag()) return true; /// is this enough?
809 bool CFileItem::IsPVRTimer() const
811 if (HasPVRTimerInfoTag()) return true; /// is this enough?
815 bool CFileItem::IsDiscStub() const
817 if (IsVideoDb() && HasVideoInfoTag())
819 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
820 return dbItem.IsDiscStub();
823 CStdString strExtension;
824 URIUtils::GetExtension(m_strPath, strExtension);
826 if (strExtension.IsEmpty())
829 strExtension.ToLower();
832 return (g_settings.m_discStubExtensions + '|').Find(strExtension) != -1;
835 bool CFileItem::IsAudio() const
837 /* check preset mime type */
838 if( m_mimetype.Left(6).Equals("audio/") )
841 if (HasMusicInfoTag()) return true;
842 if (HasVideoInfoTag()) return false;
843 if (HasPictureInfoTag()) return false;
844 if (IsCDDA()) return true;
845 if (!m_bIsFolder && IsLastFM()) return true;
847 CStdString extension;
848 if( m_mimetype.Left(12).Equals("application/") )
849 { /* check for some standard types */
850 extension = m_mimetype.Mid(12);
851 if( extension.Equals("ogg")
852 || extension.Equals("mp4")
853 || extension.Equals("mxf") )
857 URIUtils::GetExtension(m_strPath, extension);
859 if (extension.IsEmpty())
864 return (g_settings.m_musicExtensions.Find(extension) != -1);
867 bool CFileItem::IsKaraoke() const
869 if ( !IsAudio() || IsLastFM())
872 return CKaraokeLyricsFactory::HasLyrics( m_strPath );
875 bool CFileItem::IsPicture() const
877 if( m_mimetype.Left(6).Equals("image/") )
880 if (HasPictureInfoTag()) return true;
881 if (HasMusicInfoTag()) return false;
882 if (HasVideoInfoTag()) return false;
884 return CUtil::IsPicture(m_strPath);
887 bool CFileItem::IsLyrics() const
889 return URIUtils::GetExtension(m_strPath).Equals(".cdg", false) || URIUtils::GetExtension(m_strPath).Equals(".lrc", false);
892 bool CFileItem::IsCUESheet() const
894 return URIUtils::GetExtension(m_strPath).Equals(".cue", false);
897 bool CFileItem::IsLastFM() const
899 return URIUtils::IsLastFM(m_strPath);
902 bool CFileItem::IsInternetStream(const bool bStrictCheck /* = false */) const
904 if (HasProperty("IsHTTPDirectory"))
907 return URIUtils::IsInternetStream(m_strPath, bStrictCheck);
910 bool CFileItem::IsFileFolder() const
914 (IsPlayList() && g_advancedSettings.m_playlistAsFolders) ||
927 bool CFileItem::IsSmartPlayList() const
929 if (HasProperty("library.smartplaylist") && GetProperty("library.smartplaylist").asBoolean())
932 CStdString strExtension;
933 URIUtils::GetExtension(m_strPath, strExtension);
934 strExtension.ToLower();
935 return (strExtension == ".xsp");
938 bool CFileItem::IsPlayList() const
940 return CPlayListFactory::IsPlaylist(*this);
943 bool CFileItem::IsPythonScript() const
945 return URIUtils::GetExtension(m_strPath).Equals(".py", false);
948 bool CFileItem::IsType(const char *ext) const
950 return URIUtils::GetExtension(m_strPath).Equals(ext, false);
953 bool CFileItem::IsNFO() const
955 return URIUtils::GetExtension(m_strPath).Equals(".nfo", false);
958 bool CFileItem::IsDVDImage() const
960 CStdString strExtension;
961 URIUtils::GetExtension(m_strPath, strExtension);
962 return (strExtension.Equals(".img") || strExtension.Equals(".iso") || strExtension.Equals(".nrg"));
965 bool CFileItem::IsOpticalMediaFile() const
967 bool found = IsDVDFile(false, true);
973 bool CFileItem::IsDVDFile(bool bVobs /*= true*/, bool bIfos /*= true*/) const
975 CStdString strFileName = URIUtils::GetFileName(m_strPath);
978 if (strFileName.Equals("video_ts.ifo")) return true;
979 if (strFileName.Left(4).Equals("vts_") && strFileName.Right(6).Equals("_0.ifo") && strFileName.length() == 12) return true;
983 if (strFileName.Equals("video_ts.vob")) return true;
984 if (strFileName.Left(4).Equals("vts_") && strFileName.Right(4).Equals(".vob")) return true;
990 bool CFileItem::IsBDFile() const
992 CStdString strFileName = URIUtils::GetFileName(m_strPath);
993 return (strFileName.Equals("index.bdmv"));
996 bool CFileItem::IsRAR() const
998 return URIUtils::IsRAR(m_strPath);
1001 bool CFileItem::IsAPK() const
1003 return URIUtils::IsAPK(m_strPath);
1006 bool CFileItem::IsZIP() const
1008 return URIUtils::IsZIP(m_strPath);
1011 bool CFileItem::IsCBZ() const
1013 return URIUtils::GetExtension(m_strPath).Equals(".cbz", false);
1016 bool CFileItem::IsCBR() const
1018 return URIUtils::GetExtension(m_strPath).Equals(".cbr", false);
1021 bool CFileItem::IsRSS() const
1023 if (m_strPath.Left(6).Equals("rss://"))
1026 return URIUtils::GetExtension(m_strPath).Equals(".rss")
1027 || GetMimeType() == "application/rss+xml";
1030 bool CFileItem::IsAndroidApp() const
1032 return URIUtils::IsAndroidApp(m_strPath);
1035 bool CFileItem::IsStack() const
1037 return URIUtils::IsStack(m_strPath);
1040 bool CFileItem::IsPlugin() const
1042 return URIUtils::IsPlugin(m_strPath);
1045 bool CFileItem::IsScript() const
1047 return URIUtils::IsScript(m_strPath);
1050 bool CFileItem::IsAddonsPath() const
1052 return URIUtils::IsAddonsPath(m_strPath);
1055 bool CFileItem::IsSourcesPath() const
1057 return URIUtils::IsSourcesPath(m_strPath);
1060 bool CFileItem::IsMultiPath() const
1062 return URIUtils::IsMultiPath(m_strPath);
1065 bool CFileItem::IsCDDA() const
1067 return URIUtils::IsCDDA(m_strPath);
1070 bool CFileItem::IsDVD() const
1072 return URIUtils::IsDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1075 bool CFileItem::IsOnDVD() const
1077 return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1080 bool CFileItem::IsNfs() const
1082 return URIUtils::IsNfs(m_strPath);
1085 bool CFileItem::IsAfp() const
1087 return URIUtils::IsAfp(m_strPath);
1090 bool CFileItem::IsOnLAN() const
1092 return URIUtils::IsOnLAN(m_strPath);
1095 bool CFileItem::IsISO9660() const
1097 return URIUtils::IsISO9660(m_strPath);
1100 bool CFileItem::IsRemote() const
1102 return URIUtils::IsRemote(m_strPath);
1105 bool CFileItem::IsSmb() const
1107 return URIUtils::IsSmb(m_strPath);
1110 bool CFileItem::IsURL() const
1112 return URIUtils::IsURL(m_strPath);
1115 bool CFileItem::IsDAAP() const
1117 return URIUtils::IsDAAP(m_strPath);
1120 bool CFileItem::IsTuxBox() const
1122 return URIUtils::IsTuxBox(m_strPath);
1125 bool CFileItem::IsMythTV() const
1127 return URIUtils::IsMythTV(m_strPath);
1130 bool CFileItem::IsHDHomeRun() const
1132 return URIUtils::IsHDHomeRun(m_strPath);
1135 bool CFileItem::IsSlingbox() const
1137 return URIUtils::IsSlingbox(m_strPath);
1140 bool CFileItem::IsVTP() const
1142 return URIUtils::IsVTP(m_strPath);
1145 bool CFileItem::IsPVR() const
1147 return CUtil::IsPVR(m_strPath);
1150 bool CFileItem::IsLiveTV() const
1152 return URIUtils::IsLiveTV(m_strPath);
1155 bool CFileItem::IsHD() const
1157 return URIUtils::IsHD(m_strPath);
1160 bool CFileItem::IsMusicDb() const
1162 CURL url(m_strPath);
1163 return url.GetProtocol().Equals("musicdb");
1166 bool CFileItem::IsVideoDb() const
1168 CURL url(m_strPath);
1169 return url.GetProtocol().Equals("videodb");
1172 bool CFileItem::IsVirtualDirectoryRoot() const
1174 return (m_bIsFolder && m_strPath.IsEmpty());
1177 bool CFileItem::IsRemovable() const
1179 return IsOnDVD() || IsCDDA() || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE;
1182 bool CFileItem::IsReadOnly() const
1184 if (IsParentFolder()) return true;
1185 if (m_bIsShareOrDrive) return true;
1186 return !CUtil::SupportsWriteFileOperations(m_strPath);
1189 void CFileItem::FillInDefaultIcon()
1191 //CLog::Log(LOGINFO, "FillInDefaultIcon(%s)", pItem->GetLabel().c_str());
1192 // find the default icon for a file or folder item
1193 // for files this can be the (depending on the file type)
1194 // default picture for photo's
1195 // default picture for songs
1196 // default picture for videos
1197 // default picture for shortcuts
1198 // default picture for playlists
1199 // or the icon embedded in an .xbe
1202 // for .. folders the default picture for parent folder
1203 // for other folders the defaultFolder.png
1205 if (GetIconImage().IsEmpty())
1209 /* To reduce the average runtime of this code, this list should
1210 * be ordered with most frequently seen types first. Also bear
1211 * in mind the complexity of the code behind the check in the
1212 * case of IsWhatater() returns false.
1216 if (GetPVRChannelInfoTag()->IsRadio())
1217 SetIconImage("DefaultAudio.png");
1219 SetIconImage("DefaultVideo.png");
1221 else if ( IsLiveTV() )
1224 SetIconImage("DefaultVideo.png");
1226 else if ( URIUtils::IsArchive(m_strPath) )
1228 SetIconImage("DefaultFile.png");
1230 else if ( IsAudio() )
1233 SetIconImage("DefaultAudio.png");
1235 else if ( IsVideo() )
1238 SetIconImage("DefaultVideo.png");
1240 else if (IsPVRRecording())
1242 SetIconImage("DefaultVideo.png");
1244 else if (IsPVRTimer())
1246 SetIconImage("DefaultVideo.png");
1248 else if ( IsPicture() )
1251 SetIconImage("DefaultPicture.png");
1253 else if ( IsPlayList() )
1255 SetIconImage("DefaultPlaylist.png");
1257 else if ( IsPythonScript() )
1259 SetIconImage("DefaultScript.png");
1263 // default icon for unknown file type
1264 SetIconImage("DefaultFile.png");
1271 SetIconImage("DefaultPlaylist.png");
1273 else if (IsParentFolder())
1275 SetIconImage("DefaultFolderBack.png");
1279 SetIconImage("DefaultFolder.png");
1283 // Set the icon overlays (if applicable)
1286 if (URIUtils::IsInRAR(m_strPath))
1287 SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR);
1288 else if (URIUtils::IsInZIP(m_strPath))
1289 SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP);
1293 void CFileItem::RemoveExtension()
1297 CStdString strLabel = GetLabel();
1298 URIUtils::RemoveExtension(strLabel);
1302 void CFileItem::CleanString()
1307 CStdString strLabel = GetLabel();
1308 CStdString strTitle, strTitleAndYear, strYear;
1309 CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, true );
1310 SetLabel(strTitleAndYear);
1313 void CFileItem::SetLabel(const CStdString &strLabel)
1317 m_bIsParentFolder=true;
1319 m_specialSort = SortSpecialOnTop;
1320 SetLabelPreformated(true);
1322 CGUIListItem::SetLabel(strLabel);
1325 void CFileItem::SetFileSizeLabel()
1327 if( m_bIsFolder && m_dwSize == 0 )
1330 SetLabel2(StringUtils::SizeToString(m_dwSize));
1333 CURL CFileItem::GetAsUrl() const
1335 return CURL(m_strPath);
1338 bool CFileItem::CanQueue() const
1343 void CFileItem::SetCanQueue(bool bYesNo)
1348 bool CFileItem::IsParentFolder() const
1350 return m_bIsParentFolder;
1353 const CStdString& CFileItem::GetMimeType(bool lookup /*= true*/) const
1355 if( m_mimetype.IsEmpty() && lookup)
1357 // discard const qualifyier
1358 CStdString& m_ref = (CStdString&)m_mimetype;
1361 m_ref = "x-directory/normal";
1362 else if( m_pvrChannelInfoTag )
1363 m_ref = m_pvrChannelInfoTag->InputFormat();
1364 else if( m_strPath.Left(8).Equals("shout://")
1365 || m_strPath.Left(7).Equals("http://")
1366 || m_strPath.Left(8).Equals("https://"))
1368 CCurlFile::GetMimeType(GetAsUrl(), m_ref);
1370 // try to get mime-type again but with an NSPlayer User-Agent
1371 // in order for server to provide correct mime-type. Allows us
1372 // to properly detect an MMS stream
1373 if (m_ref.Left(11).Equals("video/x-ms-"))
1374 CCurlFile::GetMimeType(GetAsUrl(), m_ref, "NSPlayer/11.00.6001.7000");
1376 // make sure there are no options set in mime-type
1377 // mime-type can look like "video/x-ms-asf ; charset=utf8"
1378 int i = m_ref.Find(';');
1380 m_ref.Delete(i,m_ref.length()-i);
1384 m_ref = CMime::GetMimeType(*this);
1386 // if it's still empty set to an unknown type
1387 if( m_ref.IsEmpty() )
1388 m_ref = "application/octet-stream";
1391 // change protocol to mms for the following mome-type. Allows us to create proper FileMMS.
1392 if( m_mimetype.Left(32).Equals("application/vnd.ms.wms-hdr.asfv1") || m_mimetype.Left(24).Equals("application/x-mms-framed") )
1394 CStdString& m_path = (CStdString&)m_strPath;
1395 m_path.Replace("http:", "mms:");
1401 bool CFileItem::IsSamePath(const CFileItem *item) const
1406 if (item->GetPath() == m_strPath)
1408 if (item->HasProperty("item_start") || HasProperty("item_start"))
1409 return (item->GetProperty("item_start") == GetProperty("item_start"));
1412 if (IsMusicDb() && HasMusicInfoTag())
1414 CFileItem dbItem(m_musicInfoTag->GetURL(), false);
1415 if (HasProperty("item_start"))
1416 dbItem.SetProperty("item_start", GetProperty("item_start"));
1417 return dbItem.IsSamePath(item);
1419 if (IsVideoDb() && HasVideoInfoTag())
1421 CFileItem dbItem(m_videoInfoTag->m_strFileNameAndPath, false);
1422 if (HasProperty("item_start"))
1423 dbItem.SetProperty("item_start", GetProperty("item_start"));
1424 return dbItem.IsSamePath(item);
1426 if (item->IsMusicDb() && item->HasMusicInfoTag())
1428 CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
1429 if (item->HasProperty("item_start"))
1430 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1431 return IsSamePath(&dbItem);
1433 if (item->IsVideoDb() && item->HasVideoInfoTag())
1435 CFileItem dbItem(item->m_videoInfoTag->m_strFileNameAndPath, false);
1436 if (item->HasProperty("item_start"))
1437 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1438 return IsSamePath(&dbItem);
1440 if (HasProperty("original_listitem_url"))
1441 return (GetProperty("original_listitem_url") == item->GetPath());
1445 bool CFileItem::IsAlbum() const
1450 void CFileItem::UpdateInfo(const CFileItem &item, bool replaceLabels /*=true*/)
1452 if (item.HasVideoInfoTag())
1453 { // copy info across (TODO: premiered info is normally stored in m_dateTime by the db)
1454 *GetVideoInfoTag() = *item.GetVideoInfoTag();
1455 // preferably use some information from PVR info tag if available
1456 if (HasPVRRecordingInfoTag())
1457 GetPVRRecordingInfoTag()->CopyClientInfo(GetVideoInfoTag());
1458 SetOverlayImage(ICON_OVERLAY_UNWATCHED, GetVideoInfoTag()->m_playCount > 0);
1460 if (item.HasMusicInfoTag())
1461 *GetMusicInfoTag() = *item.GetMusicInfoTag();
1462 if (item.HasPictureInfoTag())
1463 *GetPictureInfoTag() = *item.GetPictureInfoTag();
1465 if (replaceLabels && !item.GetLabel().IsEmpty())
1466 SetLabel(item.GetLabel());
1467 if (replaceLabels && !item.GetLabel2().IsEmpty())
1468 SetLabel2(item.GetLabel2());
1469 if (!item.GetArt("thumb").empty())
1470 SetArt("thumb", item.GetArt("thumb"));
1471 if (!item.GetIconImage().IsEmpty())
1472 SetIconImage(item.GetIconImage());
1473 AppendProperties(item);
1476 void CFileItem::SetFromVideoInfoTag(const CVideoInfoTag &video)
1478 if (!video.m_strTitle.empty())
1479 SetLabel(video.m_strTitle);
1480 if (video.m_strFileNameAndPath.IsEmpty())
1482 m_strPath = video.m_strPath;
1483 URIUtils::AddSlashAtEnd(m_strPath);
1488 m_strPath = video.m_strFileNameAndPath;
1489 m_bIsFolder = false;
1492 *GetVideoInfoTag() = video;
1493 if (video.m_iSeason == 0)
1494 SetProperty("isspecial", "true");
1495 FillInDefaultIcon();
1498 void CFileItem::SetFromAlbum(const CAlbum &album)
1500 if (!album.strAlbum.empty())
1501 SetLabel(album.strAlbum);
1503 m_strLabel2 = StringUtils::Join(album.artist, g_advancedSettings.m_musicItemSeparator);
1504 GetMusicInfoTag()->SetAlbum(album);
1506 CMusicDatabase::SetPropertiesFromAlbum(*this,album);
1509 void CFileItem::SetFromSong(const CSong &song)
1511 if (!song.strTitle.empty())
1512 SetLabel(song.strTitle);
1513 if (!song.strFileName.empty())
1514 m_strPath = song.strFileName;
1515 GetMusicInfoTag()->SetSong(song);
1516 m_lStartOffset = song.iStartOffset;
1517 m_lStartPartNumber = 1;
1518 SetProperty("item_start", song.iStartOffset);
1519 m_lEndOffset = song.iEndOffset;
1520 if (!song.strThumb.empty())
1521 SetArt("thumb", song.strThumb);
1524 /////////////////////////////////////////////////////////////////////////////////
1528 //////////////////////////////////////////////////////////////////////////////////
1530 CFileItemList::CFileItemList()
1532 m_fastLookup = false;
1534 m_cacheToDisc = CACHE_IF_SLOW;
1535 m_sortMethod = SORT_METHOD_NONE;
1536 m_sortOrder = SortOrderNone;
1537 m_sortIgnoreFolders = false;
1538 m_replaceListing = false;
1541 CFileItemList::CFileItemList(const CStdString& strPath) : CFileItem(strPath, true)
1543 m_fastLookup = false;
1544 m_cacheToDisc = CACHE_IF_SLOW;
1545 m_sortMethod = SORT_METHOD_NONE;
1546 m_sortOrder = SortOrderNone;
1547 m_sortIgnoreFolders = false;
1548 m_replaceListing = false;
1551 CFileItemList::~CFileItemList()
1556 CFileItemPtr CFileItemList::operator[] (int iItem)
1561 const CFileItemPtr CFileItemList::operator[] (int iItem) const
1566 CFileItemPtr CFileItemList::operator[] (const CStdString& strPath)
1568 return Get(strPath);
1571 const CFileItemPtr CFileItemList::operator[] (const CStdString& strPath) const
1573 return Get(strPath);
1576 void CFileItemList::SetFastLookup(bool fastLookup)
1578 CSingleLock lock(m_lock);
1580 if (fastLookup && !m_fastLookup)
1581 { // generate the map
1583 for (unsigned int i=0; i < m_items.size(); i++)
1585 CFileItemPtr pItem = m_items[i];
1586 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1589 if (!fastLookup && m_fastLookup)
1591 m_fastLookup = fastLookup;
1594 bool CFileItemList::Contains(const CStdString& fileName) const
1596 CSingleLock lock(m_lock);
1599 return m_map.find(fileName) != m_map.end();
1602 for (unsigned int i = 0; i < m_items.size(); i++)
1604 const CFileItemPtr pItem = m_items[i];
1605 if (pItem->GetPath().Equals(fileName))
1611 void CFileItemList::Clear()
1613 CSingleLock lock(m_lock);
1616 m_sortMethod = SORT_METHOD_NONE;
1617 m_sortOrder = SortOrderNone;
1618 m_sortIgnoreFolders = false;
1619 m_cacheToDisc = CACHE_IF_SLOW;
1620 m_sortDetails.clear();
1621 m_replaceListing = false;
1625 void CFileItemList::ClearItems()
1627 CSingleLock lock(m_lock);
1628 // make sure we free the memory of the items (these are GUIControls which may have allocated resources)
1630 for (unsigned int i = 0; i < m_items.size(); i++)
1632 CFileItemPtr item = m_items[i];
1639 void CFileItemList::Add(const CFileItemPtr &pItem)
1641 CSingleLock lock(m_lock);
1643 m_items.push_back(pItem);
1646 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1650 void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition)
1652 CSingleLock lock(m_lock);
1654 if (itemPosition >= 0)
1656 m_items.insert(m_items.begin()+itemPosition, pItem);
1660 m_items.insert(m_items.begin()+(m_items.size()+itemPosition), pItem);
1664 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1668 void CFileItemList::Remove(CFileItem* pItem)
1670 CSingleLock lock(m_lock);
1672 for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it)
1674 if (pItem == it->get())
1679 m_map.erase(pItem->GetPath());
1686 void CFileItemList::Remove(int iItem)
1688 CSingleLock lock(m_lock);
1690 if (iItem >= 0 && iItem < (int)Size())
1692 CFileItemPtr pItem = *(m_items.begin() + iItem);
1695 m_map.erase(pItem->GetPath());
1697 m_items.erase(m_items.begin() + iItem);
1701 void CFileItemList::Append(const CFileItemList& itemlist)
1703 CSingleLock lock(m_lock);
1705 for (int i = 0; i < itemlist.Size(); ++i)
1709 void CFileItemList::Assign(const CFileItemList& itemlist, bool append)
1711 CSingleLock lock(m_lock);
1715 SetPath(itemlist.GetPath());
1716 SetLabel(itemlist.GetLabel());
1717 m_sortDetails = itemlist.m_sortDetails;
1718 m_replaceListing = itemlist.m_replaceListing;
1719 m_content = itemlist.m_content;
1720 m_mapProperties = itemlist.m_mapProperties;
1721 m_cacheToDisc = itemlist.m_cacheToDisc;
1724 bool CFileItemList::Copy(const CFileItemList& items)
1726 // assign all CFileItem parts
1727 *(CFileItem*)this = *(CFileItem*)&items;
1729 // assign the rest of the CFileItemList properties
1730 m_replaceListing = items.m_replaceListing;
1731 m_content = items.m_content;
1732 m_mapProperties = items.m_mapProperties;
1733 m_cacheToDisc = items.m_cacheToDisc;
1734 m_sortDetails = items.m_sortDetails;
1735 m_sortMethod = items.m_sortMethod;
1736 m_sortOrder = items.m_sortOrder;
1737 m_sortIgnoreFolders = items.m_sortIgnoreFolders;
1739 // make a copy of each item
1740 for (int i = 0; i < items.Size(); i++)
1742 CFileItemPtr newItem(new CFileItem(*items[i]));
1749 CFileItemPtr CFileItemList::Get(int iItem)
1751 CSingleLock lock(m_lock);
1753 if (iItem > -1 && iItem < (int)m_items.size())
1754 return m_items[iItem];
1756 return CFileItemPtr();
1759 const CFileItemPtr CFileItemList::Get(int iItem) const
1761 CSingleLock lock(m_lock);
1763 if (iItem > -1 && iItem < (int)m_items.size())
1764 return m_items[iItem];
1766 return CFileItemPtr();
1769 CFileItemPtr CFileItemList::Get(const CStdString& strPath)
1771 CSingleLock lock(m_lock);
1775 IMAPFILEITEMS it=m_map.find(strPath);
1776 if (it != m_map.end())
1779 return CFileItemPtr();
1782 for (unsigned int i = 0; i < m_items.size(); i++)
1784 CFileItemPtr pItem = m_items[i];
1785 if (pItem->GetPath().Equals(strPath))
1789 return CFileItemPtr();
1792 const CFileItemPtr CFileItemList::Get(const CStdString& strPath) const
1794 CSingleLock lock(m_lock);
1798 map<CStdString, CFileItemPtr>::const_iterator it=m_map.find(strPath);
1799 if (it != m_map.end())
1802 return CFileItemPtr();
1805 for (unsigned int i = 0; i < m_items.size(); i++)
1807 CFileItemPtr pItem = m_items[i];
1808 if (pItem->GetPath().Equals(strPath))
1812 return CFileItemPtr();
1815 int CFileItemList::Size() const
1817 CSingleLock lock(m_lock);
1818 return (int)m_items.size();
1821 bool CFileItemList::IsEmpty() const
1823 CSingleLock lock(m_lock);
1824 return (m_items.size() <= 0);
1827 void CFileItemList::Reserve(int iCount)
1829 CSingleLock lock(m_lock);
1830 m_items.reserve(iCount);
1833 void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func)
1835 CSingleLock lock(m_lock);
1836 std::stable_sort(m_items.begin(), m_items.end(), func);
1839 void CFileItemList::FillSortFields(FILEITEMFILLFUNC func)
1841 CSingleLock lock(m_lock);
1842 std::for_each(m_items.begin(), m_items.end(), func);
1845 void CFileItemList::Sort(SORT_METHOD sortMethod, SortOrder sortOrder)
1848 if (sortMethod == m_sortMethod && m_sortOrder == sortOrder)
1851 SortDescription sorting = SortUtils::TranslateOldSortMethod(sortMethod);
1852 sorting.sortOrder = sortOrder;
1856 m_sortMethod = sortMethod;
1857 m_sortOrder = sortOrder;
1860 void CFileItemList::Sort(SortDescription sortDescription)
1862 if (sortDescription.sortBy == SortByNone)
1865 if (sortDescription.sortBy == SortByFile ||
1866 sortDescription.sortBy == SortBySortTitle ||
1867 sortDescription.sortBy == SortByDateAdded ||
1868 sortDescription.sortBy == SortByRating ||
1869 sortDescription.sortBy == SortByYear ||
1870 sortDescription.sortBy == SortByPlaylistOrder ||
1871 sortDescription.sortBy == SortByLastPlayed ||
1872 sortDescription.sortBy == SortByPlaycount)
1873 sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders);
1875 if (m_sortIgnoreFolders)
1876 sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders);
1878 SortItems sortItems((size_t)Size());
1879 for (int index = 0; index < Size(); index++)
1881 m_items[index]->ToSortable(sortItems[index]);
1882 sortItems[index][FieldId] = index;
1886 SortUtils::Sort(sortDescription, sortItems);
1888 // apply the new order to the existing CFileItems
1889 VECFILEITEMS sortedFileItems;
1890 sortedFileItems.reserve(Size());
1891 for (SortItems::const_iterator it = sortItems.begin(); it != sortItems.end(); it++)
1893 CFileItemPtr item = m_items[(int)it->at(FieldId).asInteger()];
1894 // Set the sort label in the CFileItem
1895 item->SetSortLabel(CStdStringW(it->at(FieldSort).asWideString()));
1897 sortedFileItems.push_back(item);
1900 // replace the current list with the re-ordered one
1901 m_items.assign(sortedFileItems.begin(), sortedFileItems.end());
1904 void CFileItemList::Randomize()
1906 CSingleLock lock(m_lock);
1907 random_shuffle(m_items.begin(), m_items.end());
1910 void CFileItemList::Archive(CArchive& ar)
1912 CSingleLock lock(m_lock);
1915 CFileItem::Archive(ar);
1918 if (m_items.size() > 0 && m_items[0]->IsParentFolder())
1921 ar << (int)(m_items.size() - i);
1925 ar << (int)m_sortMethod;
1926 ar << (int)m_sortOrder;
1927 ar << m_sortIgnoreFolders;
1928 ar << (int)m_cacheToDisc;
1930 ar << (int)m_sortDetails.size();
1931 for (unsigned int j = 0; j < m_sortDetails.size(); ++j)
1933 const SORT_METHOD_DETAILS &details = m_sortDetails[j];
1934 ar << (int)details.m_sortMethod;
1935 ar << details.m_buttonLabel;
1936 ar << details.m_labelMasks.m_strLabelFile;
1937 ar << details.m_labelMasks.m_strLabelFolder;
1938 ar << details.m_labelMasks.m_strLabel2File;
1939 ar << details.m_labelMasks.m_strLabel2Folder;
1944 for (; i < (int)m_items.size(); ++i)
1946 CFileItemPtr pItem = m_items[i];
1952 CFileItemPtr pParent;
1955 CFileItemPtr pItem=m_items[0];
1956 if (pItem->IsParentFolder())
1957 pParent.reset(new CFileItem(*pItem));
1960 SetFastLookup(false);
1964 CFileItem::Archive(ar);
1973 m_items.reserve(iSize + 1);
1974 m_items.push_back(pParent);
1977 m_items.reserve(iSize);
1979 bool fastLookup=false;
1983 ar >> (int&)tempint;
1984 m_sortMethod = SORT_METHOD(tempint);
1985 ar >> (int&)tempint;
1986 m_sortOrder = SortOrder(tempint);
1987 ar >> m_sortIgnoreFolders;
1988 ar >> (int&)tempint;
1989 m_cacheToDisc = CACHE_TYPE(tempint);
1991 unsigned int detailSize = 0;
1993 for (unsigned int j = 0; j < detailSize; ++j)
1995 SORT_METHOD_DETAILS details;
1996 ar >> (int&)tempint;
1997 details.m_sortMethod = SORT_METHOD(tempint);
1998 ar >> details.m_buttonLabel;
1999 ar >> details.m_labelMasks.m_strLabelFile;
2000 ar >> details.m_labelMasks.m_strLabelFolder;
2001 ar >> details.m_labelMasks.m_strLabel2File;
2002 ar >> details.m_labelMasks.m_strLabel2Folder;
2003 m_sortDetails.push_back(details);
2008 for (int i = 0; i < iSize; ++i)
2010 CFileItemPtr pItem(new CFileItem);
2015 SetFastLookup(fastLookup);
2019 void CFileItemList::FillInDefaultIcons()
2021 CSingleLock lock(m_lock);
2022 for (int i = 0; i < (int)m_items.size(); ++i)
2024 CFileItemPtr pItem = m_items[i];
2025 pItem->FillInDefaultIcon();
2029 int CFileItemList::GetFolderCount() const
2031 CSingleLock lock(m_lock);
2032 int nFolderCount = 0;
2033 for (int i = 0; i < (int)m_items.size(); i++)
2035 CFileItemPtr pItem = m_items[i];
2036 if (pItem->m_bIsFolder)
2040 return nFolderCount;
2043 int CFileItemList::GetObjectCount() const
2045 CSingleLock lock(m_lock);
2047 int numObjects = (int)m_items.size();
2048 if (numObjects && m_items[0]->IsParentFolder())
2054 int CFileItemList::GetFileCount() const
2056 CSingleLock lock(m_lock);
2058 for (int i = 0; i < (int)m_items.size(); i++)
2060 CFileItemPtr pItem = m_items[i];
2061 if (!pItem->m_bIsFolder)
2068 int CFileItemList::GetSelectedCount() const
2070 CSingleLock lock(m_lock);
2072 for (int i = 0; i < (int)m_items.size(); i++)
2074 CFileItemPtr pItem = m_items[i];
2075 if (pItem->IsSelected())
2082 void CFileItemList::FilterCueItems()
2084 CSingleLock lock(m_lock);
2085 // Handle .CUE sheet files...
2086 VECSONGS itemstoadd;
2087 CStdStringArray itemstodelete;
2088 for (int i = 0; i < (int)m_items.size(); i++)
2090 CFileItemPtr pItem = m_items[i];
2091 if (!pItem->m_bIsFolder)
2092 { // see if it's a .CUE sheet
2093 if (pItem->IsCUESheet())
2095 CCueDocument cuesheet;
2096 if (cuesheet.Parse(pItem->GetPath()))
2099 cuesheet.GetSongs(newitems);
2101 std::vector<CStdString> MediaFileVec;
2102 cuesheet.GetMediaFiles(MediaFileVec);
2104 // queue the cue sheet and the underlying media file for deletion
2105 for(std::vector<CStdString>::iterator itMedia = MediaFileVec.begin(); itMedia != MediaFileVec.end(); itMedia++)
2107 CStdString strMediaFile = *itMedia;
2108 CStdString fileFromCue = strMediaFile; // save the file from the cue we're matching against,
2109 // as we're going to search for others here...
2110 bool bFoundMediaFile = CFile::Exists(strMediaFile);
2111 // queue the cue sheet and the underlying media file for deletion
2112 if (!bFoundMediaFile)
2114 // try file in same dir, not matching case...
2115 if (Contains(strMediaFile))
2117 bFoundMediaFile = true;
2121 // try removing the .cue extension...
2122 strMediaFile = pItem->GetPath();
2123 URIUtils::RemoveExtension(strMediaFile);
2124 CFileItem item(strMediaFile, false);
2125 if (item.IsAudio() && Contains(strMediaFile))
2127 bFoundMediaFile = true;
2130 { // try replacing the extension with one of our allowed ones.
2131 CStdStringArray extensions;
2132 StringUtils::SplitString(g_settings.m_musicExtensions, "|", extensions);
2133 for (unsigned int i = 0; i < extensions.size(); i++)
2135 strMediaFile = URIUtils::ReplaceExtension(pItem->GetPath(), extensions[i]);
2136 CFileItem item(strMediaFile, false);
2137 if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile))
2139 bFoundMediaFile = true;
2146 if (bFoundMediaFile)
2148 itemstodelete.push_back(pItem->GetPath());
2149 itemstodelete.push_back(strMediaFile);
2150 // get the additional stuff (year, genre etc.) from the underlying media files tag.
2152 auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(strMediaFile));
2153 if (NULL != pLoader.get())
2156 pLoader->Load(strMediaFile, tag);
2158 // fill in any missing entries from underlying media file
2159 for (int j = 0; j < (int)newitems.size(); j++)
2161 CSong song = newitems[j];
2162 // only for songs that actually match the current media file
2163 if (song.strFileName == fileFromCue)
2165 // we might have a new media file from the above matching code
2166 song.strFileName = strMediaFile;
2169 if (song.strAlbum.empty() && !tag.GetAlbum().empty()) song.strAlbum = tag.GetAlbum();
2170 if (song.albumArtist.empty() && !tag.GetAlbumArtist().empty()) song.albumArtist = tag.GetAlbumArtist();
2171 if (song.genre.empty() && !tag.GetGenre().empty()) song.genre = tag.GetGenre();
2172 if (song.artist.empty() && !tag.GetArtist().empty()) song.artist = tag.GetArtist();
2173 if (tag.GetDiscNumber()) song.iTrack |= (tag.GetDiscNumber() << 16); // see CMusicInfoTag::GetDiscNumber()
2174 SYSTEMTIME dateTime;
2175 tag.GetReleaseDate(dateTime);
2176 if (dateTime.wYear) song.iYear = dateTime.wYear;
2177 if (song.embeddedArt.empty() && !tag.GetCoverArtInfo().empty())
2178 song.embeddedArt = tag.GetCoverArtInfo();
2180 if (!song.iDuration && tag.GetDuration() > 0)
2181 { // must be the last song
2182 song.iDuration = (tag.GetDuration() * 75 - song.iStartOffset + 37) / 75;
2184 // add this item to the list
2185 itemstoadd.push_back(song);
2190 { // remove the .cue sheet from the directory
2191 itemstodelete.push_back(pItem->GetPath());
2196 { // remove the .cue sheet from the directory (can't parse it - no point listing it)
2197 itemstodelete.push_back(pItem->GetPath());
2202 // now delete the .CUE files and underlying media files.
2203 for (int i = 0; i < (int)itemstodelete.size(); i++)
2205 for (int j = 0; j < (int)m_items.size(); j++)
2207 CFileItemPtr pItem = m_items[j];
2208 if (stricmp(pItem->GetPath().c_str(), itemstodelete[i].c_str()) == 0)
2209 { // delete this item
2210 m_items.erase(m_items.begin() + j);
2215 // and add the files from the .CUE sheet
2216 for (int i = 0; i < (int)itemstoadd.size(); i++)
2218 // now create the file item, and add to the item list.
2219 CFileItemPtr pItem(new CFileItem(itemstoadd[i]));
2220 m_items.push_back(pItem);
2224 // Remove the extensions from the filenames
2225 void CFileItemList::RemoveExtensions()
2227 CSingleLock lock(m_lock);
2228 for (int i = 0; i < Size(); ++i)
2229 m_items[i]->RemoveExtension();
2232 void CFileItemList::Stack(bool stackFiles /* = true */)
2234 CSingleLock lock(m_lock);
2237 if (IsVirtualDirectoryRoot() || IsLiveTV() || IsSourcesPath())
2240 SetProperty("isstacked", true);
2242 // items needs to be sorted for stuff below to work properly
2243 Sort(SORT_METHOD_LABEL, SortOrderAscending);
2251 void CFileItemList::StackFolders()
2253 // Precompile our REs
2254 VECCREGEXP folderRegExps;
2255 CRegExp folderRegExp(true);
2256 const CStdStringArray& strFolderRegExps = g_advancedSettings.m_folderStackRegExps;
2258 CStdStringArray::const_iterator strExpression = strFolderRegExps.begin();
2259 while (strExpression != strFolderRegExps.end())
2261 if (!folderRegExp.RegComp(*strExpression))
2262 CLog::Log(LOGERROR, "%s: Invalid folder stack RegExp:'%s'", __FUNCTION__, strExpression->c_str());
2264 folderRegExps.push_back(folderRegExp);
2270 for (int i = 0; i < Size(); i++)
2272 CFileItemPtr item = Get(i);
2273 // combined the folder checks
2274 if (item->m_bIsFolder)
2276 // only check known fast sources?
2278 // 1. rars and zips may be on slow sources? is this supposed to be allowed?
2279 if( !item->IsRemote()
2283 || URIUtils::IsInRAR(item->GetPath())
2284 || URIUtils::IsInZIP(item->GetPath())
2285 || URIUtils::IsOnLAN(item->GetPath())
2288 // stack cd# folders if contains only a single video file
2292 VECCREGEXP::iterator expr = folderRegExps.begin();
2293 while (!bMatch && expr != folderRegExps.end())
2295 //CLog::Log(LOGDEBUG,"%s: Running expression %s on %s", __FUNCTION__, expr->GetPattern().c_str(), item->GetLabel().c_str());
2296 bMatch = (expr->RegFind(item->GetLabel().c_str()) != -1);
2299 CFileItemList items;
2300 CDirectory::GetDirectory(item->GetPath(),items,g_settings.m_videoExtensions);
2301 // optimized to only traverse listing once by checking for filecount
2302 // and recording last file item for later use
2305 for (int j = 0; j < items.Size(); j++)
2307 if (!items[j]->m_bIsFolder)
2318 *item = *items[index];
2323 // check for dvd folders
2328 URIUtils::AddFileToFolder(item->GetPath(), "VIDEO_TS.IFO", path);
2329 if (CFile::Exists(path))
2333 URIUtils::AddFileToFolder(item->GetPath(), "VIDEO_TS", dvdPath);
2334 URIUtils::AddFileToFolder(dvdPath, "VIDEO_TS.IFO", path);
2336 if (CFile::Exists(path))
2339 #ifdef HAVE_LIBBLURAY
2340 if (dvdPath.IsEmpty())
2342 URIUtils::AddFileToFolder(item->GetPath(), "index.bdmv", path);
2343 if (CFile::Exists(path))
2347 URIUtils::AddFileToFolder(item->GetPath(), "BDMV", dvdPath);
2348 URIUtils::AddFileToFolder(dvdPath, "index.bdmv", path);
2350 if (CFile::Exists(path))
2355 if (!dvdPath.IsEmpty())
2357 // NOTE: should this be done for the CD# folders too?
2358 item->m_bIsFolder = false;
2359 item->SetPath(dvdPath);
2360 item->SetLabel2("");
2361 item->SetLabelPreformated(true);
2362 m_sortMethod = SORT_METHOD_NONE; /* sorting is now broken */
2370 void CFileItemList::StackFiles()
2372 // Precompile our REs
2373 VECCREGEXP stackRegExps;
2374 CRegExp tmpRegExp(true);
2375 const CStdStringArray& strStackRegExps = g_advancedSettings.m_videoStackRegExps;
2376 CStdStringArray::const_iterator strRegExp = strStackRegExps.begin();
2377 while (strRegExp != strStackRegExps.end())
2379 if (tmpRegExp.RegComp(*strRegExp))
2381 if (tmpRegExp.GetCaptureTotal() == 4)
2382 stackRegExps.push_back(tmpRegExp);
2384 CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have 4 captures.", strRegExp->c_str());
2389 // now stack the files, some of which may be from the previous stack iteration
2393 CFileItemPtr item1 = Get(i);
2395 // skip folders, nfo files, playlists
2396 if (item1->m_bIsFolder
2397 || item1->IsParentFolder()
2399 || item1->IsPlayList()
2409 CStdString stackName;
2411 CStdString filePath;
2413 VECCREGEXP::iterator expr = stackRegExps.begin();
2415 URIUtils::Split(item1->GetPath(), filePath, file1);
2416 if (URIUtils::ProtocolHasEncodedFilename(CURL(filePath).GetProtocol() ) )
2417 CURL::Decode(file1);
2420 while (expr != stackRegExps.end())
2422 if (expr->RegFind(file1, offset) != -1)
2424 CStdString Title1 = expr->GetMatch(1),
2425 Volume1 = expr->GetMatch(2),
2426 Ignore1 = expr->GetMatch(3),
2427 Extension1 = expr->GetMatch(4);
2429 Title1 = file1.substr(0, expr->GetSubStart(2));
2433 CFileItemPtr item2 = Get(j);
2435 // skip folders, nfo files, playlists
2436 if (item2->m_bIsFolder
2437 || item2->IsParentFolder()
2439 || item2->IsPlayList()
2447 CStdString file2, filePath2;
2448 URIUtils::Split(item2->GetPath(), filePath2, file2);
2449 if (URIUtils::ProtocolHasEncodedFilename(CURL(filePath2).GetProtocol() ) )
2450 CURL::Decode(file2);
2452 if (expr->RegFind(file2, offset) != -1)
2454 CStdString Title2 = expr->GetMatch(1),
2455 Volume2 = expr->GetMatch(2),
2456 Ignore2 = expr->GetMatch(3),
2457 Extension2 = expr->GetMatch(4);
2459 Title2 = file2.substr(0, expr->GetSubStart(2));
2460 if (Title1.Equals(Title2))
2462 if (!Volume1.Equals(Volume2))
2464 if (Ignore1.Equals(Ignore2) && Extension1.Equals(Extension2))
2466 if (stack.size() == 0)
2468 stackName = Title1 + Ignore1 + Extension1;
2470 size += item1->m_dwSize;
2473 size += item2->m_dwSize;
2482 else if (!Ignore1.Equals(Ignore2)) // False positive, try again with offset
2484 offset = expr->GetSubStart(3);
2487 else // Extension mismatch
2494 else // Title mismatch
2501 else // No match 2, next expression
2510 expr = stackRegExps.end();
2517 if (stack.size() > 1)
2519 // have a stack, remove the items and add the stacked item
2520 // dont actually stack a multipart rar set, just remove all items but the first
2521 CStdString stackPath;
2522 if (Get(stack[0])->IsRAR())
2523 stackPath = Get(stack[0])->GetPath();
2526 CStackDirectory dir;
2527 stackPath = dir.ConstructStackPath(*this, stack);
2529 item1->SetPath(stackPath);
2531 for (unsigned k = 1; k < stack.size(); k++)
2533 // item->m_bIsFolder = true; // don't treat stacked files as folders
2534 // the label may be in a different char set from the filename (eg over smb
2535 // the label is converted from utf8, but the filename is not)
2536 if (!g_guiSettings.GetBool("filelists.showextensions"))
2537 URIUtils::RemoveExtension(stackName);
2539 item1->SetLabel(stackName);
2540 item1->m_dwSize = size;
2548 bool CFileItemList::Load(int windowID)
2551 if (file.Open(GetDiscFileCache(windowID)))
2553 CLog::Log(LOGDEBUG,"Loading fileitems [%s]",GetPath().c_str());
2554 CArchive ar(&file, CArchive::load);
2556 CLog::Log(LOGDEBUG," -- items: %i, directory: %s sort method: %i, ascending: %s",Size(),GetPath().c_str(), m_sortMethod, m_sortOrder ? "true" : "false");
2565 bool CFileItemList::Save(int windowID)
2571 CLog::Log(LOGDEBUG,"Saving fileitems [%s]",GetPath().c_str());
2574 if (file.OpenForWrite(GetDiscFileCache(windowID), true)) // overwrite always
2576 CArchive ar(&file, CArchive::store);
2578 CLog::Log(LOGDEBUG," -- items: %i, sort method: %i, ascending: %s",iSize,m_sortMethod, m_sortOrder ? "true" : "false");
2587 void CFileItemList::RemoveDiscCache(int windowID) const
2589 CStdString cacheFile(GetDiscFileCache(windowID));
2590 if (CFile::Exists(cacheFile))
2592 CLog::Log(LOGDEBUG,"Clearing cached fileitems [%s]",GetPath().c_str());
2593 CFile::Delete(cacheFile);
2597 CStdString CFileItemList::GetDiscFileCache(int windowID) const
2599 CStdString strPath(GetPath());
2600 URIUtils::RemoveSlashAtEnd(strPath);
2603 crc.ComputeFromLowerCase(strPath);
2605 CStdString cacheFile;
2606 if (IsCDDA() || IsOnDVD())
2607 cacheFile.Format("special://temp/r-%08x.fi", (unsigned __int32)crc);
2608 else if (IsMusicDb())
2609 cacheFile.Format("special://temp/mdb-%08x.fi", (unsigned __int32)crc);
2610 else if (IsVideoDb())
2611 cacheFile.Format("special://temp/vdb-%08x.fi", (unsigned __int32)crc);
2612 else if (IsSmartPlayList())
2613 cacheFile.Format("special://temp/sp-%08x.fi", (unsigned __int32)crc);
2615 cacheFile.Format("special://temp/%i-%08x.fi", windowID, (unsigned __int32)crc);
2617 cacheFile.Format("special://temp/%08x.fi", (unsigned __int32)crc);
2621 bool CFileItemList::AlwaysCache() const
2623 // some database folders are always cached
2625 return CMusicDatabaseDirectory::CanCache(GetPath());
2627 return CVideoDatabaseDirectory::CanCache(GetPath());
2629 return true; // always cache
2633 CStdString CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */, bool fallbackToFolder /* = false */) const
2635 if (m_strPath.IsEmpty()
2636 || m_strPath.Left(19).Equals("newsmartplaylist://")
2637 || m_strPath.Left(14).Equals("newplaylist://")
2638 || m_bIsShareOrDrive
2639 || IsInternetStream()
2640 || URIUtils::IsUPnP(m_strPath)
2641 || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
2648 // we first check for <filename>.tbn or <foldername>.tbn
2649 CStdString fileThumb(GetTBNFile());
2650 if (CFile::Exists(fileThumb))
2653 // Fall back to folder thumb, if requested
2654 if (!m_bIsFolder && fallbackToFolder)
2656 CFileItem item(URIUtils::GetDirectory(m_strPath), true);
2657 return item.GetUserMusicThumb(alwaysCheckRemote);
2660 // if a folder, check for folder.jpg
2661 if (m_bIsFolder && !IsFileFolder() && (!IsRemote() || alwaysCheckRemote || g_guiSettings.GetBool("musicfiles.findremotethumbs")))
2663 CStdStringArray thumbs;
2664 StringUtils::SplitString(g_advancedSettings.m_musicThumbs, "|", thumbs);
2665 for (unsigned int i = 0; i < thumbs.size(); ++i)
2667 CStdString folderThumb(GetFolderThumb(thumbs[i]));
2668 if (CFile::Exists(folderThumb))
2678 // Gets the .tbn filename from a file or folder name.
2679 // <filename>.ext -> <filename>.tbn
2680 // <foldername>/ -> <foldername>.tbn
2681 CStdString CFileItem::GetTBNFile() const
2683 CStdString thumbFile;
2684 CStdString strFile = m_strPath;
2688 CStdString strPath, strReturn;
2689 URIUtils::GetParentPath(m_strPath,strPath);
2690 CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2691 CStdString strTBNFile = item.GetTBNFile();
2692 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strReturn);
2693 if (CFile::Exists(strReturn))
2696 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)),strFile);
2699 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2701 CStdString strPath, strParent;
2702 URIUtils::GetDirectory(strFile,strPath);
2703 URIUtils::GetParentPath(strPath,strParent);
2704 URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
2708 strFile = url.GetFileName();
2710 if (m_bIsFolder && !IsFileFolder())
2711 URIUtils::RemoveSlashAtEnd(strFile);
2713 if (!strFile.IsEmpty())
2715 if (m_bIsFolder && !IsFileFolder())
2716 thumbFile = strFile + ".tbn"; // folder, so just add ".tbn"
2718 thumbFile = URIUtils::ReplaceExtension(strFile, ".tbn");
2719 url.SetFileName(thumbFile);
2720 thumbFile = url.Get();
2725 CStdString CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) const
2727 // ignore a bunch that are meaningless
2728 if (m_strPath.empty()
2729 || m_strPath.Left(19).Equals("newsmartplaylist://")
2730 || m_strPath.Left(14).Equals("newplaylist://")
2731 || m_bIsShareOrDrive
2732 || IsInternetStream()
2733 || URIUtils::IsUPnP(m_strPath)
2734 || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
2745 thumb = GetLocalArt(artFile, false);
2746 if (!thumb.empty() && CFile::Exists(thumb))
2749 if ((useFolder || (m_bIsFolder && !IsFileFolder())) && !artFile.empty())
2751 CStdString thumb2 = GetLocalArt(artFile, true);
2752 if (!thumb2.empty() && thumb2 != thumb && CFile::Exists(thumb2))
2758 CStdString CFileItem::GetLocalArt(const std::string &artFile, bool useFolder) const
2760 // no retrieving of empty art files from folders
2761 if (useFolder && artFile.empty())
2764 CStdString strFile = m_strPath;
2767 /* CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2768 CStdString localArt = item.GetLocalArt(artFile);
2772 URIUtils::GetParentPath(m_strPath,strPath);
2773 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)),strFile);
2776 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2778 CStdString strPath, strParent;
2779 URIUtils::GetDirectory(strFile,strPath);
2780 URIUtils::GetParentPath(strPath,strParent);
2781 URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(strFile),strFile);
2785 strFile = CMultiPathDirectory::GetFirstPath(m_strPath);
2787 if (IsOpticalMediaFile())
2788 { // optical media files should be treated like folders
2790 strFile = GetLocalMetadataPath();
2792 else if (useFolder && !(m_bIsFolder && !IsFileFolder()))
2793 strFile = URIUtils::GetDirectory(strFile);
2795 if (strFile.empty()) // empty filepath -> nothing to find
2800 if (!artFile.empty())
2801 return URIUtils::AddFileToFolder(strFile, artFile);
2805 if (artFile.empty()) // old thumbnail matching
2806 return URIUtils::ReplaceExtension(strFile, ".tbn");
2808 return URIUtils::ReplaceExtension(strFile, "-" + artFile);
2813 CStdString CFileItem::GetFolderThumb(const CStdString &folderJPG /* = "folder.jpg" */) const
2815 CStdString folderThumb;
2816 CStdString strFolder = m_strPath;
2819 URIUtils::IsInRAR(strFolder) ||
2820 URIUtils::IsInZIP(strFolder))
2822 URIUtils::GetParentPath(m_strPath,strFolder);
2826 strFolder = CMultiPathDirectory::GetFirstPath(m_strPath);
2828 URIUtils::AddFileToFolder(strFolder, folderJPG, folderThumb);
2832 CStdString CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const
2834 if (IsLabelPreformated())
2837 if (m_pvrRecordingInfoTag)
2838 return m_pvrRecordingInfoTag->m_strTitle;
2839 else if (CUtil::IsTVRecording(m_strPath))
2841 CStdString title = CPVRRecording::GetTitleFromURL(m_strPath);
2842 if (!title.IsEmpty())
2846 CStdString strMovieName = GetBaseMoviePath(bUseFolderNames);
2848 if (URIUtils::IsStack(strMovieName))
2849 strMovieName = CStackDirectory::GetStackedTitlePath(strMovieName);
2851 URIUtils::RemoveSlashAtEnd(strMovieName);
2852 strMovieName = URIUtils::GetFileName(strMovieName);
2853 CURL::Decode(strMovieName);
2855 return strMovieName;
2858 CStdString CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
2860 CStdString strMovieName = m_strPath;
2863 strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
2865 if (IsOpticalMediaFile())
2866 return GetLocalMetadataPath();
2868 if ((!m_bIsFolder || URIUtils::IsInArchive(m_strPath)) && bUseFolderNames)
2870 CStdString name2(strMovieName);
2871 URIUtils::GetParentPath(name2,strMovieName);
2872 if (URIUtils::IsInArchive(m_strPath))
2874 CStdString strArchivePath;
2875 URIUtils::GetParentPath(strMovieName, strArchivePath);
2876 strMovieName = strArchivePath;
2880 return strMovieName;
2883 CStdString CFileItem::GetLocalFanart() const
2887 if (!HasVideoInfoTag())
2888 return ""; // nothing can be done
2889 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
2890 return dbItem.GetLocalFanart();
2893 CStdString strFile2;
2894 CStdString strFile = m_strPath;
2898 URIUtils::GetParentPath(m_strPath,strPath);
2899 CStackDirectory dir;
2900 CStdString strPath2;
2901 strPath2 = dir.GetStackedTitlePath(strFile);
2902 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2),strFile);
2903 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
2904 CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-fanart"));
2905 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strFile2);
2907 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2909 CStdString strPath, strParent;
2910 URIUtils::GetDirectory(strFile,strPath);
2911 URIUtils::GetParentPath(strPath,strParent);
2912 URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
2915 // no local fanart available for these
2916 if (IsInternetStream()
2917 || URIUtils::IsUPnP(strFile)
2918 || URIUtils::IsBluray(strFile)
2923 || (URIUtils::IsFTP(strFile) && !g_advancedSettings.m_bFTPThumbs)
2924 || m_strPath.IsEmpty())
2928 URIUtils::GetDirectory(strFile, strDir);
2930 if (strDir.IsEmpty())
2933 CFileItemList items;
2934 CDirectory::GetDirectory(strDir, items, g_settings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
2935 if (IsOpticalMediaFile())
2936 { // grab from the optical media parent folder as well
2937 CFileItemList moreItems;
2938 CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems, g_settings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
2939 items.Append(moreItems);
2942 CStdStringArray fanarts;
2943 StringUtils::SplitString(g_advancedSettings.m_fanartImages, "|", fanarts);
2945 strFile = URIUtils::ReplaceExtension(strFile, "-fanart");
2946 fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile));
2948 if (!strFile2.IsEmpty())
2949 fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile2));
2951 for (unsigned int i = 0; i < fanarts.size(); ++i)
2953 for (int j = 0; j < items.Size(); j++)
2955 CStdString strCandidate = URIUtils::GetFileName(items[j]->m_strPath);
2956 URIUtils::RemoveExtension(strCandidate);
2957 CStdString strFanart = fanarts[i];
2958 URIUtils::RemoveExtension(strFanart);
2959 if (strCandidate.CompareNoCase(strFanart) == 0)
2960 return items[j]->m_strPath;
2967 CStdString CFileItem::GetLocalMetadataPath() const
2969 if (m_bIsFolder && !IsFileFolder())
2972 CStdString parent(URIUtils::GetParentPath(m_strPath));
2973 CStdString parentFolder(parent);
2974 URIUtils::RemoveSlashAtEnd(parentFolder);
2975 parentFolder = URIUtils::GetFileName(parentFolder);
2976 if (parentFolder.CompareNoCase("VIDEO_TS") == 0 || parentFolder.CompareNoCase("BDMV") == 0)
2977 { // go back up another one
2978 parent = URIUtils::GetParentPath(parent);
2983 bool CFileItem::LoadMusicTag()
2989 if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
2992 CMusicDatabase musicDatabase;
2993 if (musicDatabase.Open())
2996 if (musicDatabase.GetSongByFileName(m_strPath, song))
2998 GetMusicInfoTag()->SetSong(song);
2999 SetArt("thumb", song.strThumb);
3002 musicDatabase.Close();
3004 // load tag from file
3005 CLog::Log(LOGDEBUG, "%s: loading tag information for file: %s", __FUNCTION__, m_strPath.c_str());
3006 CMusicInfoTagLoaderFactory factory;
3007 auto_ptr<IMusicInfoTagLoader> pLoader (factory.CreateLoader(m_strPath));
3008 if (NULL != pLoader.get())
3010 if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
3013 // no tag - try some other things
3016 // we have the tracknumber...
3017 int iTrack = GetMusicInfoTag()->GetTrackNumber();
3020 CStdString strText = g_localizeStrings.Get(554); // "Track"
3021 if (strText.GetAt(strText.size() - 1) != ' ')
3023 CStdString strTrack;
3024 strTrack.Format(strText + "%i", iTrack);
3025 GetMusicInfoTag()->SetTitle(strTrack);
3026 GetMusicInfoTag()->SetLoaded(true);
3032 CStdString fileName = URIUtils::GetFileName(m_strPath);
3033 URIUtils::RemoveExtension(fileName);
3034 for (unsigned int i = 0; i < g_advancedSettings.m_musicTagsFromFileFilters.size(); i++)
3036 CLabelFormatter formatter(g_advancedSettings.m_musicTagsFromFileFilters[i], "");
3037 if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
3039 GetMusicInfoTag()->SetLoaded(true);
3047 void CFileItemList::Swap(unsigned int item1, unsigned int item2)
3049 if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size())
3050 std::swap(m_items[item1], m_items[item2]);
3053 bool CFileItemList::UpdateItem(const CFileItem *item)
3055 if (!item) return false;
3057 CSingleLock lock(m_lock);
3058 for (unsigned int i = 0; i < m_items.size(); i++)
3060 CFileItemPtr pItem = m_items[i];
3061 if (pItem->IsSamePath(item))
3063 pItem->UpdateInfo(*item);
3070 void CFileItemList::AddSortMethod(SORT_METHOD sortMethod, int buttonLabel, const LABEL_MASKS &labelMasks)
3072 SORT_METHOD_DETAILS sort;
3073 sort.m_sortMethod=sortMethod;
3074 sort.m_buttonLabel=buttonLabel;
3075 sort.m_labelMasks=labelMasks;
3077 m_sortDetails.push_back(sort);
3080 void CFileItemList::SetReplaceListing(bool replace)
3082 m_replaceListing = replace;
3085 void CFileItemList::ClearSortState()
3087 m_sortMethod = SORT_METHOD_NONE;
3088 m_sortOrder = SortOrderNone;
3091 CVideoInfoTag* CFileItem::GetVideoInfoTag()
3093 if (!m_videoInfoTag)
3094 m_videoInfoTag = new CVideoInfoTag;
3096 return m_videoInfoTag;
3099 CEpgInfoTag* CFileItem::GetEPGInfoTag()
3102 m_epgInfoTag = new CEpgInfoTag;
3104 return m_epgInfoTag;
3107 CPVRChannel* CFileItem::GetPVRChannelInfoTag()
3109 if (!m_pvrChannelInfoTag)
3110 m_pvrChannelInfoTag = new CPVRChannel;
3112 return m_pvrChannelInfoTag;
3115 CPVRRecording* CFileItem::GetPVRRecordingInfoTag()
3117 if (!m_pvrRecordingInfoTag)
3118 m_pvrRecordingInfoTag = new CPVRRecording;
3120 return m_pvrRecordingInfoTag;
3123 CPVRTimerInfoTag* CFileItem::GetPVRTimerInfoTag()
3125 if (!m_pvrTimerInfoTag)
3126 m_pvrTimerInfoTag = new CPVRTimerInfoTag;
3128 return m_pvrTimerInfoTag;
3131 CPictureInfoTag* CFileItem::GetPictureInfoTag()
3133 if (!m_pictureInfoTag)
3134 m_pictureInfoTag = new CPictureInfoTag;
3136 return m_pictureInfoTag;
3139 MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
3141 if (!m_musicInfoTag)
3142 m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
3144 return m_musicInfoTag;
3147 CStdString CFileItem::FindTrailer() const
3149 CStdString strFile2;
3150 CStdString strFile = m_strPath;
3154 URIUtils::GetParentPath(m_strPath,strPath);
3155 CStackDirectory dir;
3156 CStdString strPath2;
3157 strPath2 = dir.GetStackedTitlePath(strFile);
3158 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2),strFile);
3159 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
3160 CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-trailer"));
3161 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strFile2);
3163 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
3165 CStdString strPath, strParent;
3166 URIUtils::GetDirectory(strFile,strPath);
3167 URIUtils::GetParentPath(strPath,strParent);
3168 URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
3171 // no local trailer available for these
3172 if (IsInternetStream()
3173 || URIUtils::IsUPnP(strFile)
3174 || URIUtils::IsBluray(strFile)
3181 URIUtils::GetDirectory(strFile, strDir);
3182 CFileItemList items;
3183 CDirectory::GetDirectory(strDir, items, g_settings.m_videoExtensions, DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
3184 URIUtils::RemoveExtension(strFile);
3185 strFile += "-trailer";
3186 CStdString strFile3 = URIUtils::AddFileToFolder(strDir, "movie-trailer");
3188 // Precompile our REs
3189 VECCREGEXP matchRegExps;
3190 CRegExp tmpRegExp(true);
3191 const CStdStringArray& strMatchRegExps = g_advancedSettings.m_trailerMatchRegExps;
3193 CStdStringArray::const_iterator strRegExp = strMatchRegExps.begin();
3194 while (strRegExp != strMatchRegExps.end())
3196 if (tmpRegExp.RegComp(*strRegExp))
3198 matchRegExps.push_back(tmpRegExp);
3203 CStdString strTrailer;
3204 for (int i = 0; i < items.Size(); i++)
3206 CStdString strCandidate = items[i]->m_strPath;
3207 URIUtils::RemoveExtension(strCandidate);
3208 if (strCandidate.CompareNoCase(strFile) == 0 ||
3209 strCandidate.CompareNoCase(strFile2) == 0 ||
3210 strCandidate.CompareNoCase(strFile3) == 0)
3212 strTrailer = items[i]->m_strPath;
3217 VECCREGEXP::iterator expr = matchRegExps.begin();
3219 while (expr != matchRegExps.end())
3221 if (expr->RegFind(strCandidate) != -1)
3223 strTrailer = items[i]->m_strPath;
3235 int CFileItem::GetVideoContentType() const
3237 VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
3238 if (HasVideoInfoTag() && !GetVideoInfoTag()->m_strShowTitle.IsEmpty()) // tvshow
3239 type = VIDEODB_CONTENT_TVSHOWS;
3240 if (HasVideoInfoTag() && GetVideoInfoTag()->m_iSeason > -1 && !m_bIsFolder) // episode
3241 type = VIDEODB_CONTENT_EPISODES;
3242 if (HasVideoInfoTag() && !GetVideoInfoTag()->m_artist.empty())
3243 type = VIDEODB_CONTENT_MUSICVIDEOS;