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());
155 FillInMimeType(false);
158 CFileItem::CFileItem(const CPVRChannel& channel)
160 m_musicInfoTag = NULL;
161 m_videoInfoTag = NULL;
163 m_pvrChannelInfoTag = NULL;
164 m_pvrRecordingInfoTag = NULL;
165 m_pvrTimerInfoTag = NULL;
166 m_pictureInfoTag = NULL;
170 bool bHasEpgNow = channel.GetEPGNow(epgNow);
172 m_strPath = channel.Path();
174 *GetPVRChannelInfoTag() = channel;
175 SetLabel(channel.ChannelName());
176 m_strLabel2 = bHasEpgNow ? epgNow.Title() :
177 CSettings::Get().GetBool("epg.hidenoinfoavailable") ?
178 StringUtils::EmptyString :
179 g_localizeStrings.Get(19055); // no information available
181 if (channel.IsRadio())
183 CMusicInfoTag* musictag = GetMusicInfoTag();
186 musictag->SetURL(channel.Path());
187 musictag->SetTitle(m_strLabel2);
188 musictag->SetArtist(channel.ChannelName());
189 musictag->SetAlbumArtist(channel.ChannelName());
191 musictag->SetGenre(epgNow.Genre());
192 musictag->SetDuration(bHasEpgNow ? epgNow.GetDuration() : 3600);
193 musictag->SetLoaded(true);
194 musictag->SetComment("");
195 musictag->SetLyrics("");
199 if (!channel.IconPath().empty())
200 SetIconImage(channel.IconPath());
202 SetProperty("channelid", channel.ChannelID());
203 SetProperty("path", channel.Path());
204 SetArt("thumb", channel.IconPath());
206 FillInMimeType(false);
209 CFileItem::CFileItem(const CPVRRecording& record)
211 m_musicInfoTag = NULL;
212 m_videoInfoTag = NULL;
214 m_pvrChannelInfoTag = NULL;
215 m_pvrRecordingInfoTag = NULL;
216 m_pvrTimerInfoTag = NULL;
217 m_pictureInfoTag = NULL;
221 m_strPath = record.m_strFileNameAndPath;
223 *GetPVRRecordingInfoTag() = record;
224 SetLabel(record.m_strTitle);
225 m_strLabel2 = record.m_strPlot;
227 FillInMimeType(false);
230 CFileItem::CFileItem(const CPVRTimerInfoTag& timer)
232 m_musicInfoTag = NULL;
233 m_videoInfoTag = NULL;
235 m_pvrChannelInfoTag = NULL;
236 m_pvrRecordingInfoTag = NULL;
237 m_pvrTimerInfoTag = NULL;
238 m_pictureInfoTag = NULL;
242 m_strPath = timer.Path();
244 *GetPVRTimerInfoTag() = timer;
245 SetLabel(timer.Title());
246 m_strLabel2 = timer.Summary();
247 m_dateTime = timer.StartAsLocalTime();
249 if (!timer.ChannelIcon().empty())
250 SetIconImage(timer.ChannelIcon());
252 FillInMimeType(false);
255 CFileItem::CFileItem(const CArtist& artist)
257 m_musicInfoTag = NULL;
258 m_videoInfoTag = NULL;
260 m_pvrChannelInfoTag = NULL;
261 m_pvrRecordingInfoTag = NULL;
262 m_pvrTimerInfoTag = NULL;
263 m_pictureInfoTag = NULL;
265 SetLabel(artist.strArtist);
266 m_strPath = artist.strArtist;
268 URIUtils::AddSlashAtEnd(m_strPath);
269 GetMusicInfoTag()->SetArtist(artist.strArtist);
270 FillInMimeType(false);
273 CFileItem::CFileItem(const CGenre& genre)
275 m_musicInfoTag = NULL;
276 m_videoInfoTag = NULL;
278 m_pvrChannelInfoTag = NULL;
279 m_pvrRecordingInfoTag = NULL;
280 m_pvrTimerInfoTag = NULL;
281 m_pictureInfoTag = NULL;
283 SetLabel(genre.strGenre);
284 m_strPath = genre.strGenre;
286 URIUtils::AddSlashAtEnd(m_strPath);
287 GetMusicInfoTag()->SetGenre(genre.strGenre);
288 FillInMimeType(false);
291 CFileItem::CFileItem(const CFileItem& item): CGUIListItem()
293 m_musicInfoTag = NULL;
294 m_videoInfoTag = NULL;
296 m_pvrChannelInfoTag = NULL;
297 m_pvrRecordingInfoTag = NULL;
298 m_pvrTimerInfoTag = NULL;
299 m_pictureInfoTag = NULL;
303 CFileItem::CFileItem(const CGUIListItem& item)
305 m_musicInfoTag = NULL;
306 m_videoInfoTag = NULL;
308 m_pvrChannelInfoTag = NULL;
309 m_pvrRecordingInfoTag = NULL;
310 m_pvrTimerInfoTag = NULL;
311 m_pictureInfoTag = NULL;
313 // not particularly pretty, but it gets around the issue of Reset() defaulting
314 // parameters in the CGUIListItem base class.
315 *((CGUIListItem *)this) = item;
317 FillInMimeType(false);
320 CFileItem::CFileItem(void)
322 m_musicInfoTag = NULL;
323 m_videoInfoTag = NULL;
325 m_pvrChannelInfoTag = NULL;
326 m_pvrRecordingInfoTag = NULL;
327 m_pvrTimerInfoTag = NULL;
328 m_pictureInfoTag = NULL;
332 CFileItem::CFileItem(const CStdString& strLabel)
335 m_musicInfoTag = NULL;
336 m_videoInfoTag = NULL;
338 m_pvrChannelInfoTag = NULL;
339 m_pvrRecordingInfoTag = NULL;
340 m_pvrTimerInfoTag = NULL;
341 m_pictureInfoTag = NULL;
346 CFileItem::CFileItem(const CStdString& strPath, bool bIsFolder)
348 m_musicInfoTag = NULL;
349 m_videoInfoTag = NULL;
351 m_pvrChannelInfoTag = NULL;
352 m_pvrRecordingInfoTag = NULL;
353 m_pvrTimerInfoTag = NULL;
354 m_pictureInfoTag = NULL;
357 m_bIsFolder = bIsFolder;
358 // tuxbox urls cannot have a / at end
359 if (m_bIsFolder && !m_strPath.empty() && !IsFileFolder() && !URIUtils::IsTuxBox(m_strPath))
360 URIUtils::AddSlashAtEnd(m_strPath);
361 FillInMimeType(false);
364 CFileItem::CFileItem(const CMediaSource& share)
366 m_musicInfoTag = NULL;
367 m_videoInfoTag = NULL;
369 m_pvrChannelInfoTag = NULL;
370 m_pvrRecordingInfoTag = NULL;
371 m_pvrTimerInfoTag = NULL;
372 m_pictureInfoTag = NULL;
375 m_bIsShareOrDrive = true;
376 m_strPath = share.strPath;
377 if (!IsRSS()) // no slash at end for rss feeds
378 URIUtils::AddSlashAtEnd(m_strPath);
379 CStdString label = share.strName;
380 if (!share.strStatus.empty())
381 label = StringUtils::Format("%s (%s)", share.strName.c_str(), share.strStatus.c_str());
383 m_iLockMode = share.m_iLockMode;
384 m_strLockCode = share.m_strLockCode;
385 m_iHasLock = share.m_iHasLock;
386 m_iBadPwdCount = share.m_iBadPwdCount;
387 m_iDriveType = share.m_iDriveType;
388 SetArt("thumb", share.m_strThumbnailImage);
389 SetLabelPreformated(true);
391 GetVideoInfoTag()->m_strFileNameAndPath = share.strDiskUniqueId; // share.strDiskUniqueId contains disc unique id
392 FillInMimeType(false);
395 CFileItem::~CFileItem(void)
397 delete m_musicInfoTag;
398 delete m_videoInfoTag;
400 delete m_pvrChannelInfoTag;
401 delete m_pvrRecordingInfoTag;
402 delete m_pvrTimerInfoTag;
403 delete m_pictureInfoTag;
405 m_musicInfoTag = NULL;
406 m_videoInfoTag = NULL;
408 m_pvrChannelInfoTag = NULL;
409 m_pvrRecordingInfoTag = NULL;
410 m_pvrTimerInfoTag = NULL;
411 m_pictureInfoTag = NULL;
414 const CFileItem& CFileItem::operator=(const CFileItem& item)
416 if (this == &item) return * this;
417 CGUIListItem::operator=(item);
418 m_bLabelPreformated=item.m_bLabelPreformated;
420 m_strPath = item.GetPath();
421 m_bIsParentFolder = item.m_bIsParentFolder;
422 m_iDriveType = item.m_iDriveType;
423 m_bIsShareOrDrive = item.m_bIsShareOrDrive;
424 m_dateTime = item.m_dateTime;
425 m_dwSize = item.m_dwSize;
426 if (item.HasMusicInfoTag())
428 m_musicInfoTag = GetMusicInfoTag();
430 *m_musicInfoTag = *item.m_musicInfoTag;
434 delete m_musicInfoTag;
435 m_musicInfoTag = NULL;
438 if (item.HasVideoInfoTag())
440 m_videoInfoTag = GetVideoInfoTag();
442 *m_videoInfoTag = *item.m_videoInfoTag;
446 delete m_videoInfoTag;
447 m_videoInfoTag = NULL;
450 if (item.HasEPGInfoTag())
452 m_epgInfoTag = GetEPGInfoTag();
454 *m_epgInfoTag = *item.m_epgInfoTag;
464 if (item.HasPVRChannelInfoTag())
466 m_pvrChannelInfoTag = GetPVRChannelInfoTag();
467 if (m_pvrChannelInfoTag)
468 *m_pvrChannelInfoTag = *item.m_pvrChannelInfoTag;
472 if (m_pvrChannelInfoTag)
473 delete m_pvrChannelInfoTag;
475 m_pvrChannelInfoTag = NULL;
478 if (item.HasPVRRecordingInfoTag())
480 m_pvrRecordingInfoTag = GetPVRRecordingInfoTag();
481 if (m_pvrRecordingInfoTag)
482 *m_pvrRecordingInfoTag = *item.m_pvrRecordingInfoTag;
486 if (m_pvrRecordingInfoTag)
487 delete m_pvrRecordingInfoTag;
489 m_pvrRecordingInfoTag = NULL;
492 if (item.HasPVRTimerInfoTag())
494 m_pvrTimerInfoTag = GetPVRTimerInfoTag();
495 if (m_pvrTimerInfoTag)
496 *m_pvrTimerInfoTag = *item.m_pvrTimerInfoTag;
500 if (m_pvrTimerInfoTag)
501 delete m_pvrTimerInfoTag;
503 m_pvrTimerInfoTag = NULL;
506 if (item.HasPictureInfoTag())
508 m_pictureInfoTag = GetPictureInfoTag();
509 if (m_pictureInfoTag)
510 *m_pictureInfoTag = *item.m_pictureInfoTag;
514 delete m_pictureInfoTag;
515 m_pictureInfoTag = NULL;
518 m_lStartOffset = item.m_lStartOffset;
519 m_lStartPartNumber = item.m_lStartPartNumber;
520 m_lEndOffset = item.m_lEndOffset;
521 m_strDVDLabel = item.m_strDVDLabel;
522 m_strTitle = item.m_strTitle;
523 m_iprogramCount = item.m_iprogramCount;
524 m_idepth = item.m_idepth;
525 m_iLockMode = item.m_iLockMode;
526 m_strLockCode = item.m_strLockCode;
527 m_iHasLock = item.m_iHasLock;
528 m_iBadPwdCount = item.m_iBadPwdCount;
529 m_bCanQueue=item.m_bCanQueue;
530 m_mimetype = item.m_mimetype;
531 m_extrainfo = item.m_extrainfo;
532 m_specialSort = item.m_specialSort;
533 m_bIsAlbum = item.m_bIsAlbum;
537 void CFileItem::Reset()
541 m_bLabelPreformated=false;
543 m_overlayIcon = ICON_OVERLAY_NONE;
546 m_strDVDLabel.clear();
551 m_bIsParentFolder=false;
552 m_bIsShareOrDrive = false;
554 m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
556 m_lStartPartNumber = 1;
560 m_iLockMode = LOCK_MODE_EVERYONE;
566 delete m_musicInfoTag;
568 delete m_videoInfoTag;
572 delete m_pvrChannelInfoTag;
573 m_pvrChannelInfoTag=NULL;
574 delete m_pvrRecordingInfoTag;
575 m_pvrRecordingInfoTag=NULL;
576 delete m_pvrTimerInfoTag;
577 m_pvrTimerInfoTag=NULL;
578 delete m_pictureInfoTag;
579 m_pictureInfoTag=NULL;
581 m_specialSort = SortSpecialNone;
586 void CFileItem::Archive(CArchive& ar)
588 CGUIListItem::Archive(ar);
592 ar << m_bIsParentFolder;
593 ar << m_bLabelPreformated;
595 ar << m_bIsShareOrDrive;
601 ar << m_iprogramCount;
603 ar << m_lStartOffset;
604 ar << m_lStartPartNumber;
608 ar << m_iBadPwdCount;
618 ar << *m_musicInfoTag;
625 ar << *m_videoInfoTag;
629 if (m_pictureInfoTag)
632 ar << *m_pictureInfoTag;
639 ar >> m_bIsParentFolder;
640 ar >> m_bLabelPreformated;
642 ar >> m_bIsShareOrDrive;
648 ar >> m_iprogramCount;
650 ar >> m_lStartOffset;
651 ar >> m_lStartPartNumber;
655 m_iLockMode = (LockType)temp;
657 ar >> m_iBadPwdCount;
663 m_specialSort = (SortSpecial)temp;
668 ar >> *GetMusicInfoTag();
671 ar >> *GetVideoInfoTag();
674 ar >> *GetPictureInfoTag();
680 void CFileItem::Serialize(CVariant& value) const
682 //CGUIListItem::Serialize(value["CGUIListItem"]);
684 value["strPath"] = m_strPath;
685 value["dateTime"] = (m_dateTime.IsValid()) ? m_dateTime.GetAsRFC1123DateTime() : "";
686 value["size"] = m_dwSize;
687 value["DVDLabel"] = m_strDVDLabel;
688 value["title"] = m_strTitle;
689 value["mimetype"] = m_mimetype;
690 value["extrainfo"] = m_extrainfo;
693 (*m_musicInfoTag).Serialize(value["musicInfoTag"]);
696 (*m_videoInfoTag).Serialize(value["videoInfoTag"]);
698 if (m_pictureInfoTag)
699 (*m_pictureInfoTag).Serialize(value["pictureInfoTag"]);
702 void CFileItem::ToSortable(SortItem &sortable, Field field) const
706 case FieldPath: sortable[FieldPath] = m_strPath; break;
707 case FieldDate: sortable[FieldDate] = (m_dateTime.IsValid()) ? m_dateTime.GetAsDBDateTime() : ""; break;
708 case FieldSize: sortable[FieldSize] = m_dwSize; break;
709 case FieldDriveType: sortable[FieldDriveType] = m_iDriveType; break;
710 case FieldStartOffset: sortable[FieldStartOffset] = m_lStartOffset; break;
711 case FieldEndOffset: sortable[FieldEndOffset] = m_lEndOffset; break;
712 case FieldProgramCount: sortable[FieldProgramCount] = m_iprogramCount; break;
713 case FieldBitrate: sortable[FieldBitrate] = m_dwSize; break;
714 case FieldTitle: sortable[FieldTitle] = m_strTitle; break;
715 // If there's ever a need to convert more properties from CGUIListItem it might be
716 // worth to make CGUIListItem implement ISortable as well and call it from here
720 if (HasMusicInfoTag())
721 GetMusicInfoTag()->ToSortable(sortable, field);
723 if (HasVideoInfoTag())
725 GetVideoInfoTag()->ToSortable(sortable, field);
727 if (GetVideoInfoTag()->m_type == "tvshow")
729 if (field == FieldNumberOfEpisodes && HasProperty("totalepisodes"))
730 sortable[FieldNumberOfEpisodes] = GetProperty("totalepisodes");
731 if (field == FieldNumberOfWatchedEpisodes && HasProperty("unwatchedepisodes"))
732 sortable[FieldNumberOfWatchedEpisodes] = GetProperty("unwatchedepisodes");
736 if (HasPictureInfoTag())
737 GetPictureInfoTag()->ToSortable(sortable, field);
739 if (HasPVRChannelInfoTag())
740 GetPVRChannelInfoTag()->ToSortable(sortable, field);
743 void CFileItem::ToSortable(SortItem &sortable, const Fields &fields) const
745 Fields::const_iterator it;
746 for (it = fields.begin(); it != fields.end(); it++)
747 ToSortable(sortable, *it);
749 /* FieldLabel is used as a fallback by all sorters and therefore has to be present as well */
750 sortable[FieldLabel] = GetLabel();
751 /* FieldSortSpecial and FieldFolder are required in conjunction with all other sorters as well */
752 sortable[FieldSortSpecial] = m_specialSort;
753 sortable[FieldFolder] = m_bIsFolder;
756 bool CFileItem::Exists(bool bUseCache /* = true */) const
758 if (m_strPath.empty()
759 || m_strPath.Equals("add")
760 || IsInternetStream()
762 || IsVirtualDirectoryRoot()
766 if (IsVideoDb() && HasVideoInfoTag())
768 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
769 return dbItem.Exists();
772 CStdString strPath = m_strPath;
774 if (URIUtils::IsMultiPath(strPath))
775 strPath = CMultiPathDirectory::GetFirstPath(strPath);
777 if (URIUtils::IsStack(strPath))
778 strPath = CStackDirectory::GetFirstStackedFile(strPath);
781 return CDirectory::Exists(strPath);
783 return CFile::Exists(strPath, bUseCache);
788 bool CFileItem::IsVideo() const
790 /* check preset mime type */
791 if( StringUtils::StartsWithNoCase(m_mimetype, "video/") )
794 if (HasVideoInfoTag()) return true;
795 if (HasMusicInfoTag()) return false;
796 if (HasPictureInfoTag()) return false;
797 if (IsPVRRecording()) return true;
799 if (IsHDHomeRun() || IsTuxBox() || URIUtils::IsDVD(m_strPath) || IsSlingbox())
802 CStdString extension;
803 if( StringUtils::StartsWithNoCase(m_mimetype, "application/") )
804 { /* check for some standard types */
805 extension = m_mimetype.Mid(12);
806 if( extension.Equals("ogg")
807 || extension.Equals("mp4")
808 || extension.Equals("mxf") )
812 return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_videoExtensions);
815 bool CFileItem::IsEPG() const
817 if (HasEPGInfoTag()) return true; /// is this enough?
821 bool CFileItem::IsPVRChannel() const
823 if (HasPVRChannelInfoTag()) return true; /// is this enough?
827 bool CFileItem::IsPVRRecording() const
829 if (HasPVRRecordingInfoTag()) return true; /// is this enough?
833 bool CFileItem::IsPVRTimer() const
835 if (HasPVRTimerInfoTag()) return true; /// is this enough?
839 bool CFileItem::IsDiscStub() const
841 if (IsVideoDb() && HasVideoInfoTag())
843 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
844 return dbItem.IsDiscStub();
847 return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_discStubExtensions);
850 bool CFileItem::IsAudio() const
852 /* check preset mime type */
853 if( StringUtils::StartsWithNoCase(m_mimetype, "audio/") )
856 if (HasMusicInfoTag()) return true;
857 if (HasVideoInfoTag()) return false;
858 if (HasPictureInfoTag()) return false;
859 if (IsCDDA()) return true;
861 if( StringUtils::StartsWithNoCase(m_mimetype, "application/") )
862 { /* check for some standard types */
863 CStdString extension = m_mimetype.Mid(12);
864 if( extension.Equals("ogg")
865 || extension.Equals("mp4")
866 || extension.Equals("mxf") )
870 return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_musicExtensions);
873 bool CFileItem::IsKaraoke() const
878 return CKaraokeLyricsFactory::HasLyrics( m_strPath );
881 bool CFileItem::IsPicture() const
883 if( StringUtils::StartsWithNoCase(m_mimetype, "image/") )
886 if (HasPictureInfoTag()) return true;
887 if (HasMusicInfoTag()) return false;
888 if (HasVideoInfoTag()) return false;
890 return CUtil::IsPicture(m_strPath);
893 bool CFileItem::IsLyrics() const
895 return URIUtils::HasExtension(m_strPath, ".cdg|.lrc");
898 bool CFileItem::IsCUESheet() const
900 return URIUtils::HasExtension(m_strPath, ".cue");
903 bool CFileItem::IsInternetStream(const bool bStrictCheck /* = false */) const
905 if (HasProperty("IsHTTPDirectory"))
908 return URIUtils::IsInternetStream(m_strPath, bStrictCheck);
911 bool CFileItem::IsFileFolder(EFileFolderType types) const
913 EFileFolderType always_type = EFILEFOLDER_TYPE_ALWAYS;
915 /* internet streams are not directly expanded */
916 if(IsInternetStream())
917 always_type = EFILEFOLDER_TYPE_ONCLICK;
920 if(types & always_type)
922 if( IsSmartPlayList()
923 || (IsPlayList() && g_advancedSettings.m_playlistAsFolders)
928 || IsType(".ogg|.oga|.nsf|.sid|.sap|.xsp")
929 #if defined(TARGET_ANDROID)
932 #ifdef HAS_ASAP_CODEC
933 || ASAPCodec::IsSupportedFormat(URIUtils::GetExtension(m_strPath))
939 if(types & EFILEFOLDER_TYPE_ONBROWSE)
941 if((IsPlayList() && !g_advancedSettings.m_playlistAsFolders)
950 bool CFileItem::IsSmartPlayList() const
952 if (HasProperty("library.smartplaylist") && GetProperty("library.smartplaylist").asBoolean())
955 return URIUtils::HasExtension(m_strPath, ".xsp");
958 bool CFileItem::IsLibraryFolder() const
960 if (HasProperty("library.filter") && GetProperty("library.filter").asBoolean())
963 return URIUtils::IsLibraryFolder(m_strPath);
966 bool CFileItem::IsPlayList() const
968 return CPlayListFactory::IsPlaylist(*this);
971 bool CFileItem::IsPythonScript() const
973 return URIUtils::HasExtension(m_strPath, ".py");
976 bool CFileItem::IsType(const char *ext) const
978 return URIUtils::HasExtension(m_strPath, ext);
981 bool CFileItem::IsNFO() const
983 return URIUtils::HasExtension(m_strPath, ".nfo");
986 bool CFileItem::IsDVDImage() const
988 return URIUtils::HasExtension(m_strPath, ".img|.iso|.nrg");
991 bool CFileItem::IsOpticalMediaFile() const
993 bool found = IsDVDFile(false, true);
999 bool CFileItem::IsDVDFile(bool bVobs /*= true*/, bool bIfos /*= true*/) const
1001 CStdString strFileName = URIUtils::GetFileName(m_strPath);
1004 if (strFileName.Equals("video_ts.ifo")) return true;
1005 if (StringUtils::StartsWithNoCase(strFileName, "vts_") && StringUtils::EndsWithNoCase(strFileName, "_0.ifo") && strFileName.length() == 12) return true;
1009 if (strFileName.Equals("video_ts.vob")) return true;
1010 if (StringUtils::StartsWithNoCase(strFileName, "vts_") && StringUtils::EndsWithNoCase(strFileName, ".vob")) return true;
1016 bool CFileItem::IsBDFile() const
1018 CStdString strFileName = URIUtils::GetFileName(m_strPath);
1019 return (strFileName.Equals("index.bdmv"));
1022 bool CFileItem::IsRAR() const
1024 return URIUtils::IsRAR(m_strPath);
1027 bool CFileItem::IsAPK() const
1029 return URIUtils::IsAPK(m_strPath);
1032 bool CFileItem::IsZIP() const
1034 return URIUtils::IsZIP(m_strPath);
1037 bool CFileItem::IsCBZ() const
1039 return URIUtils::HasExtension(m_strPath, ".cbz");
1042 bool CFileItem::IsCBR() const
1044 return URIUtils::HasExtension(m_strPath, ".cbr");
1047 bool CFileItem::IsRSS() const
1049 return StringUtils::StartsWithNoCase(m_strPath, "rss://") || URIUtils::HasExtension(m_strPath, ".rss")
1050 || m_mimetype == "application/rss+xml";
1053 bool CFileItem::IsAndroidApp() const
1055 return URIUtils::IsAndroidApp(m_strPath);
1058 bool CFileItem::IsStack() const
1060 return URIUtils::IsStack(m_strPath);
1063 bool CFileItem::IsPlugin() const
1065 return URIUtils::IsPlugin(m_strPath);
1068 bool CFileItem::IsScript() const
1070 return URIUtils::IsScript(m_strPath);
1073 bool CFileItem::IsAddonsPath() const
1075 return URIUtils::IsAddonsPath(m_strPath);
1078 bool CFileItem::IsSourcesPath() const
1080 return URIUtils::IsSourcesPath(m_strPath);
1083 bool CFileItem::IsMultiPath() const
1085 return URIUtils::IsMultiPath(m_strPath);
1088 bool CFileItem::IsCDDA() const
1090 return URIUtils::IsCDDA(m_strPath);
1093 bool CFileItem::IsDVD() const
1095 return URIUtils::IsDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1098 bool CFileItem::IsOnDVD() const
1100 return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1103 bool CFileItem::IsNfs() const
1105 return URIUtils::IsNfs(m_strPath);
1108 bool CFileItem::IsAfp() const
1110 return URIUtils::IsAfp(m_strPath);
1113 bool CFileItem::IsOnLAN() const
1115 return URIUtils::IsOnLAN(m_strPath);
1118 bool CFileItem::IsISO9660() const
1120 return URIUtils::IsISO9660(m_strPath);
1123 bool CFileItem::IsRemote() const
1125 return URIUtils::IsRemote(m_strPath);
1128 bool CFileItem::IsSmb() const
1130 return URIUtils::IsSmb(m_strPath);
1133 bool CFileItem::IsURL() const
1135 return URIUtils::IsURL(m_strPath);
1138 bool CFileItem::IsDAAP() const
1140 return URIUtils::IsDAAP(m_strPath);
1143 bool CFileItem::IsTuxBox() const
1145 return URIUtils::IsTuxBox(m_strPath);
1148 bool CFileItem::IsMythTV() const
1150 return URIUtils::IsMythTV(m_strPath);
1153 bool CFileItem::IsHDHomeRun() const
1155 return URIUtils::IsHDHomeRun(m_strPath);
1158 bool CFileItem::IsSlingbox() const
1160 return URIUtils::IsSlingbox(m_strPath);
1163 bool CFileItem::IsVTP() const
1165 return URIUtils::IsVTP(m_strPath);
1168 bool CFileItem::IsPVR() const
1170 return CUtil::IsPVR(m_strPath);
1173 bool CFileItem::IsLiveTV() const
1175 return URIUtils::IsLiveTV(m_strPath);
1178 bool CFileItem::IsHD() const
1180 return URIUtils::IsHD(m_strPath);
1183 bool CFileItem::IsMusicDb() const
1185 CURL url(m_strPath);
1186 return url.GetProtocol().Equals("musicdb");
1189 bool CFileItem::IsVideoDb() const
1191 CURL url(m_strPath);
1192 return url.GetProtocol().Equals("videodb");
1195 bool CFileItem::IsVirtualDirectoryRoot() const
1197 return (m_bIsFolder && m_strPath.empty());
1200 bool CFileItem::IsRemovable() const
1202 return IsOnDVD() || IsCDDA() || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE;
1205 bool CFileItem::IsReadOnly() const
1207 if (IsParentFolder()) return true;
1208 if (m_bIsShareOrDrive) return true;
1209 return !CUtil::SupportsWriteFileOperations(m_strPath);
1212 void CFileItem::FillInDefaultIcon()
1214 //CLog::Log(LOGINFO, "FillInDefaultIcon(%s)", pItem->GetLabel().c_str());
1215 // find the default icon for a file or folder item
1216 // for files this can be the (depending on the file type)
1217 // default picture for photo's
1218 // default picture for songs
1219 // default picture for videos
1220 // default picture for shortcuts
1221 // default picture for playlists
1222 // or the icon embedded in an .xbe
1225 // for .. folders the default picture for parent folder
1226 // for other folders the defaultFolder.png
1228 if (GetIconImage().empty())
1232 /* To reduce the average runtime of this code, this list should
1233 * be ordered with most frequently seen types first. Also bear
1234 * in mind the complexity of the code behind the check in the
1235 * case of IsWhatater() returns false.
1239 if (GetPVRChannelInfoTag()->IsRadio())
1240 SetIconImage("DefaultAudio.png");
1242 SetIconImage("DefaultVideo.png");
1244 else if ( IsLiveTV() )
1247 SetIconImage("DefaultVideo.png");
1249 else if ( URIUtils::IsArchive(m_strPath) )
1251 SetIconImage("DefaultFile.png");
1253 else if ( IsAudio() )
1256 SetIconImage("DefaultAudio.png");
1258 else if ( IsVideo() )
1261 SetIconImage("DefaultVideo.png");
1263 else if (IsPVRRecording())
1265 SetIconImage("DefaultVideo.png");
1267 else if (IsPVRTimer())
1269 SetIconImage("DefaultVideo.png");
1271 else if ( IsPicture() )
1274 SetIconImage("DefaultPicture.png");
1276 else if ( IsPlayList() )
1278 SetIconImage("DefaultPlaylist.png");
1280 else if ( IsPythonScript() )
1282 SetIconImage("DefaultScript.png");
1286 // default icon for unknown file type
1287 SetIconImage("DefaultFile.png");
1294 SetIconImage("DefaultPlaylist.png");
1296 else if (IsParentFolder())
1298 SetIconImage("DefaultFolderBack.png");
1302 SetIconImage("DefaultFolder.png");
1306 // Set the icon overlays (if applicable)
1309 if (URIUtils::IsInRAR(m_strPath))
1310 SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR);
1311 else if (URIUtils::IsInZIP(m_strPath))
1312 SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP);
1316 void CFileItem::RemoveExtension()
1320 CStdString strLabel = GetLabel();
1321 URIUtils::RemoveExtension(strLabel);
1325 void CFileItem::CleanString()
1330 CStdString strLabel = GetLabel();
1331 CStdString strTitle, strTitleAndYear, strYear;
1332 CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, true );
1333 SetLabel(strTitleAndYear);
1336 void CFileItem::SetLabel(const CStdString &strLabel)
1340 m_bIsParentFolder=true;
1342 m_specialSort = SortSpecialOnTop;
1343 SetLabelPreformated(true);
1345 CGUIListItem::SetLabel(strLabel);
1348 void CFileItem::SetFileSizeLabel()
1350 if( m_bIsFolder && m_dwSize == 0 )
1353 SetLabel2(StringUtils::SizeToString(m_dwSize));
1356 CURL CFileItem::GetAsUrl() const
1358 return CURL(m_strPath);
1361 bool CFileItem::CanQueue() const
1366 void CFileItem::SetCanQueue(bool bYesNo)
1371 bool CFileItem::IsParentFolder() const
1373 return m_bIsParentFolder;
1376 void CFileItem::FillInMimeType(bool lookup /*= true*/)
1378 if (m_mimetype.empty())
1381 m_mimetype = "x-directory/normal";
1382 else if( m_pvrChannelInfoTag )
1383 m_mimetype = m_pvrChannelInfoTag->InputFormat();
1384 else if( StringUtils::StartsWithNoCase(m_strPath, "shout://")
1385 || StringUtils::StartsWithNoCase(m_strPath, "http://")
1386 || StringUtils::StartsWithNoCase(m_strPath, "https://"))
1388 // If lookup is false, bail out early to leave mime type empty
1392 CCurlFile::GetMimeType(GetAsUrl(), m_mimetype);
1394 // try to get mime-type again but with an NSPlayer User-Agent
1395 // in order for server to provide correct mime-type. Allows us
1396 // to properly detect an MMS stream
1397 if (StringUtils::StartsWithNoCase(m_mimetype, "video/x-ms-"))
1398 CCurlFile::GetMimeType(GetAsUrl(), m_mimetype, "NSPlayer/11.00.6001.7000");
1400 // make sure there are no options set in mime-type
1401 // mime-type can look like "video/x-ms-asf ; charset=utf8"
1402 int i = m_mimetype.Find(';');
1404 m_mimetype.Delete(i, m_mimetype.length() - i);
1405 StringUtils::Trim(m_mimetype);
1408 m_mimetype = CMime::GetMimeType(*this);
1410 // if it's still empty set to an unknown type
1411 if (m_mimetype.empty())
1412 m_mimetype = "application/octet-stream";
1415 // change protocol to mms for the following mime-type. Allows us to create proper FileMMS.
1416 if( StringUtils::StartsWithNoCase(m_mimetype, "application/vnd.ms.wms-hdr.asfv1") || StringUtils::StartsWithNoCase(m_mimetype, "application/x-mms-framed") )
1417 m_strPath.Replace("http:", "mms:");
1420 bool CFileItem::IsSamePath(const CFileItem *item) const
1425 if (item->GetPath() == m_strPath)
1427 if (item->HasProperty("item_start") || HasProperty("item_start"))
1428 return (item->GetProperty("item_start") == GetProperty("item_start"));
1431 if (IsMusicDb() && HasMusicInfoTag())
1433 CFileItem dbItem(m_musicInfoTag->GetURL(), false);
1434 if (HasProperty("item_start"))
1435 dbItem.SetProperty("item_start", GetProperty("item_start"));
1436 return dbItem.IsSamePath(item);
1438 if (IsVideoDb() && HasVideoInfoTag())
1440 CFileItem dbItem(m_videoInfoTag->m_strFileNameAndPath, false);
1441 if (HasProperty("item_start"))
1442 dbItem.SetProperty("item_start", GetProperty("item_start"));
1443 return dbItem.IsSamePath(item);
1445 if (item->IsMusicDb() && item->HasMusicInfoTag())
1447 CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
1448 if (item->HasProperty("item_start"))
1449 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1450 return IsSamePath(&dbItem);
1452 if (item->IsVideoDb() && item->HasVideoInfoTag())
1454 CFileItem dbItem(item->m_videoInfoTag->m_strFileNameAndPath, false);
1455 if (item->HasProperty("item_start"))
1456 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1457 return IsSamePath(&dbItem);
1459 if (HasProperty("original_listitem_url"))
1460 return (GetProperty("original_listitem_url") == item->GetPath());
1464 bool CFileItem::IsAlbum() const
1469 void CFileItem::UpdateInfo(const CFileItem &item, bool replaceLabels /*=true*/)
1471 if (item.HasVideoInfoTag())
1472 { // copy info across (TODO: premiered info is normally stored in m_dateTime by the db)
1473 *GetVideoInfoTag() = *item.GetVideoInfoTag();
1474 // preferably use some information from PVR info tag if available
1475 if (HasPVRRecordingInfoTag())
1476 GetPVRRecordingInfoTag()->CopyClientInfo(GetVideoInfoTag());
1477 SetOverlayImage(ICON_OVERLAY_UNWATCHED, GetVideoInfoTag()->m_playCount > 0);
1479 if (item.HasMusicInfoTag())
1480 *GetMusicInfoTag() = *item.GetMusicInfoTag();
1481 if (item.HasPictureInfoTag())
1482 *GetPictureInfoTag() = *item.GetPictureInfoTag();
1484 if (replaceLabels && !item.GetLabel().empty())
1485 SetLabel(item.GetLabel());
1486 if (replaceLabels && !item.GetLabel2().empty())
1487 SetLabel2(item.GetLabel2());
1488 if (!item.GetArt("thumb").empty())
1489 SetArt("thumb", item.GetArt("thumb"));
1490 if (!item.GetIconImage().empty())
1491 SetIconImage(item.GetIconImage());
1492 AppendProperties(item);
1495 void CFileItem::SetFromVideoInfoTag(const CVideoInfoTag &video)
1497 if (!video.m_strTitle.empty())
1498 SetLabel(video.m_strTitle);
1499 if (video.m_strFileNameAndPath.empty())
1501 m_strPath = video.m_strPath;
1502 URIUtils::AddSlashAtEnd(m_strPath);
1507 m_strPath = video.m_strFileNameAndPath;
1508 m_bIsFolder = false;
1511 *GetVideoInfoTag() = video;
1512 if (video.m_iSeason == 0)
1513 SetProperty("isspecial", "true");
1514 FillInDefaultIcon();
1515 FillInMimeType(false);
1518 void CFileItem::SetFromAlbum(const CAlbum &album)
1520 if (!album.strAlbum.empty())
1521 SetLabel(album.strAlbum);
1523 m_strLabel2 = StringUtils::Join(album.artist, g_advancedSettings.m_musicItemSeparator);
1524 GetMusicInfoTag()->SetAlbum(album);
1526 CMusicDatabase::SetPropertiesFromAlbum(*this,album);
1527 FillInMimeType(false);
1530 void CFileItem::SetFromSong(const CSong &song)
1532 if (!song.strTitle.empty())
1533 SetLabel(song.strTitle);
1534 if (!song.strFileName.empty())
1535 m_strPath = song.strFileName;
1536 GetMusicInfoTag()->SetSong(song);
1537 m_lStartOffset = song.iStartOffset;
1538 m_lStartPartNumber = 1;
1539 SetProperty("item_start", song.iStartOffset);
1540 m_lEndOffset = song.iEndOffset;
1541 if (!song.strThumb.empty())
1542 SetArt("thumb", song.strThumb);
1543 FillInMimeType(false);
1546 /////////////////////////////////////////////////////////////////////////////////
1550 //////////////////////////////////////////////////////////////////////////////////
1552 CFileItemList::CFileItemList()
1554 m_fastLookup = false;
1556 m_cacheToDisc = CACHE_IF_SLOW;
1557 m_sortIgnoreFolders = false;
1558 m_replaceListing = false;
1561 CFileItemList::CFileItemList(const CStdString& strPath) : CFileItem(strPath, true)
1563 m_fastLookup = false;
1564 m_cacheToDisc = CACHE_IF_SLOW;
1565 m_sortIgnoreFolders = false;
1566 m_replaceListing = false;
1569 CFileItemList::~CFileItemList()
1574 CFileItemPtr CFileItemList::operator[] (int iItem)
1579 const CFileItemPtr CFileItemList::operator[] (int iItem) const
1584 CFileItemPtr CFileItemList::operator[] (const CStdString& strPath)
1586 return Get(strPath);
1589 const CFileItemPtr CFileItemList::operator[] (const CStdString& strPath) const
1591 return Get(strPath);
1594 void CFileItemList::SetFastLookup(bool fastLookup)
1596 CSingleLock lock(m_lock);
1598 if (fastLookup && !m_fastLookup)
1599 { // generate the map
1601 for (unsigned int i=0; i < m_items.size(); i++)
1603 CFileItemPtr pItem = m_items[i];
1604 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1607 if (!fastLookup && m_fastLookup)
1609 m_fastLookup = fastLookup;
1612 bool CFileItemList::Contains(const CStdString& fileName) const
1614 CSingleLock lock(m_lock);
1617 return m_map.find(fileName) != m_map.end();
1620 for (unsigned int i = 0; i < m_items.size(); i++)
1622 const CFileItemPtr pItem = m_items[i];
1623 if (pItem->GetPath().Equals(fileName))
1629 void CFileItemList::Clear()
1631 CSingleLock lock(m_lock);
1634 m_sortDescription.sortBy = SortByNone;
1635 m_sortDescription.sortOrder = SortOrderNone;
1636 m_sortDescription.sortAttributes = SortAttributeNone;
1637 m_sortIgnoreFolders = false;
1638 m_cacheToDisc = CACHE_IF_SLOW;
1639 m_sortDetails.clear();
1640 m_replaceListing = false;
1644 void CFileItemList::ClearItems()
1646 CSingleLock lock(m_lock);
1647 // make sure we free the memory of the items (these are GUIControls which may have allocated resources)
1649 for (unsigned int i = 0; i < m_items.size(); i++)
1651 CFileItemPtr item = m_items[i];
1658 void CFileItemList::Add(const CFileItemPtr &pItem)
1660 CSingleLock lock(m_lock);
1662 m_items.push_back(pItem);
1665 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1669 void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition)
1671 CSingleLock lock(m_lock);
1673 if (itemPosition >= 0)
1675 m_items.insert(m_items.begin()+itemPosition, pItem);
1679 m_items.insert(m_items.begin()+(m_items.size()+itemPosition), pItem);
1683 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1687 void CFileItemList::Remove(CFileItem* pItem)
1689 CSingleLock lock(m_lock);
1691 for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it)
1693 if (pItem == it->get())
1698 m_map.erase(pItem->GetPath());
1705 void CFileItemList::Remove(int iItem)
1707 CSingleLock lock(m_lock);
1709 if (iItem >= 0 && iItem < (int)Size())
1711 CFileItemPtr pItem = *(m_items.begin() + iItem);
1714 m_map.erase(pItem->GetPath());
1716 m_items.erase(m_items.begin() + iItem);
1720 void CFileItemList::Append(const CFileItemList& itemlist)
1722 CSingleLock lock(m_lock);
1724 for (int i = 0; i < itemlist.Size(); ++i)
1728 void CFileItemList::Assign(const CFileItemList& itemlist, bool append)
1730 CSingleLock lock(m_lock);
1734 SetPath(itemlist.GetPath());
1735 SetLabel(itemlist.GetLabel());
1736 m_sortDetails = itemlist.m_sortDetails;
1737 m_sortDescription = itemlist.m_sortDescription;
1738 m_replaceListing = itemlist.m_replaceListing;
1739 m_content = itemlist.m_content;
1740 m_mapProperties = itemlist.m_mapProperties;
1741 m_cacheToDisc = itemlist.m_cacheToDisc;
1744 bool CFileItemList::Copy(const CFileItemList& items, bool copyItems /* = true */)
1746 // assign all CFileItem parts
1747 *(CFileItem*)this = *(CFileItem*)&items;
1749 // assign the rest of the CFileItemList properties
1750 m_replaceListing = items.m_replaceListing;
1751 m_content = items.m_content;
1752 m_mapProperties = items.m_mapProperties;
1753 m_cacheToDisc = items.m_cacheToDisc;
1754 m_sortDetails = items.m_sortDetails;
1755 m_sortDescription = items.m_sortDescription;
1756 m_sortIgnoreFolders = items.m_sortIgnoreFolders;
1760 // make a copy of each item
1761 for (int i = 0; i < items.Size(); i++)
1763 CFileItemPtr newItem(new CFileItem(*items[i]));
1771 CFileItemPtr CFileItemList::Get(int iItem)
1773 CSingleLock lock(m_lock);
1775 if (iItem > -1 && iItem < (int)m_items.size())
1776 return m_items[iItem];
1778 return CFileItemPtr();
1781 const CFileItemPtr CFileItemList::Get(int iItem) const
1783 CSingleLock lock(m_lock);
1785 if (iItem > -1 && iItem < (int)m_items.size())
1786 return m_items[iItem];
1788 return CFileItemPtr();
1791 CFileItemPtr CFileItemList::Get(const CStdString& strPath)
1793 CSingleLock lock(m_lock);
1797 IMAPFILEITEMS it=m_map.find(strPath);
1798 if (it != m_map.end())
1801 return CFileItemPtr();
1804 for (unsigned int i = 0; i < m_items.size(); i++)
1806 CFileItemPtr pItem = m_items[i];
1807 if (pItem->GetPath().Equals(strPath))
1811 return CFileItemPtr();
1814 const CFileItemPtr CFileItemList::Get(const CStdString& strPath) const
1816 CSingleLock lock(m_lock);
1820 map<CStdString, CFileItemPtr>::const_iterator it=m_map.find(strPath);
1821 if (it != m_map.end())
1824 return CFileItemPtr();
1827 for (unsigned int i = 0; i < m_items.size(); i++)
1829 CFileItemPtr pItem = m_items[i];
1830 if (pItem->GetPath().Equals(strPath))
1834 return CFileItemPtr();
1837 int CFileItemList::Size() const
1839 CSingleLock lock(m_lock);
1840 return (int)m_items.size();
1843 bool CFileItemList::IsEmpty() const
1845 CSingleLock lock(m_lock);
1846 return (m_items.size() <= 0);
1849 void CFileItemList::Reserve(int iCount)
1851 CSingleLock lock(m_lock);
1852 m_items.reserve(iCount);
1855 void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func)
1857 CSingleLock lock(m_lock);
1858 std::stable_sort(m_items.begin(), m_items.end(), func);
1861 void CFileItemList::FillSortFields(FILEITEMFILLFUNC func)
1863 CSingleLock lock(m_lock);
1864 std::for_each(m_items.begin(), m_items.end(), func);
1867 void CFileItemList::Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute sortAttributes /* = SortAttributeNone */)
1869 if (sortBy == SortByNone ||
1870 (m_sortDescription.sortBy == sortBy && m_sortDescription.sortOrder == sortOrder &&
1871 m_sortDescription.sortAttributes == sortAttributes))
1874 SortDescription sorting;
1875 sorting.sortBy = sortBy;
1876 sorting.sortOrder = sortOrder;
1877 sorting.sortAttributes = sortAttributes;
1880 m_sortDescription = sorting;
1883 void CFileItemList::Sort(SortDescription sortDescription)
1885 if (sortDescription.sortBy == SortByFile ||
1886 sortDescription.sortBy == SortBySortTitle ||
1887 sortDescription.sortBy == SortByDateAdded ||
1888 sortDescription.sortBy == SortByRating ||
1889 sortDescription.sortBy == SortByYear ||
1890 sortDescription.sortBy == SortByPlaylistOrder ||
1891 sortDescription.sortBy == SortByLastPlayed ||
1892 sortDescription.sortBy == SortByPlaycount)
1893 sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders);
1895 if (sortDescription.sortBy == SortByNone ||
1896 (m_sortDescription.sortBy == sortDescription.sortBy && m_sortDescription.sortOrder == sortDescription.sortOrder &&
1897 m_sortDescription.sortAttributes == sortDescription.sortAttributes))
1900 if (m_sortIgnoreFolders)
1901 sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders);
1903 const Fields fields = SortUtils::GetFieldsForSorting(sortDescription.sortBy);
1904 SortItems sortItems((size_t)Size());
1905 for (int index = 0; index < Size(); index++)
1907 sortItems[index] = boost::shared_ptr<SortItem>(new SortItem);
1908 m_items[index]->ToSortable(*sortItems[index], fields);
1909 (*sortItems[index])[FieldId] = index;
1913 SortUtils::Sort(sortDescription, sortItems);
1915 // apply the new order to the existing CFileItems
1916 VECFILEITEMS sortedFileItems;
1917 sortedFileItems.reserve(Size());
1918 for (SortItems::const_iterator it = sortItems.begin(); it != sortItems.end(); it++)
1920 CFileItemPtr item = m_items[(int)(*it)->at(FieldId).asInteger()];
1921 // Set the sort label in the CFileItem
1922 item->SetSortLabel(CStdStringW((*it)->at(FieldSort).asWideString()));
1924 sortedFileItems.push_back(item);
1927 // replace the current list with the re-ordered one
1928 m_items.assign(sortedFileItems.begin(), sortedFileItems.end());
1931 void CFileItemList::Randomize()
1933 CSingleLock lock(m_lock);
1934 random_shuffle(m_items.begin(), m_items.end());
1937 void CFileItemList::Archive(CArchive& ar)
1939 CSingleLock lock(m_lock);
1942 CFileItem::Archive(ar);
1945 if (m_items.size() > 0 && m_items[0]->IsParentFolder())
1948 ar << (int)(m_items.size() - i);
1952 ar << (int)m_sortDescription.sortBy;
1953 ar << (int)m_sortDescription.sortOrder;
1954 ar << (int)m_sortDescription.sortAttributes;
1955 ar << m_sortIgnoreFolders;
1956 ar << (int)m_cacheToDisc;
1958 ar << (int)m_sortDetails.size();
1959 for (unsigned int j = 0; j < m_sortDetails.size(); ++j)
1961 const SORT_METHOD_DETAILS &details = m_sortDetails[j];
1962 ar << (int)details.m_sortDescription.sortBy;
1963 ar << (int)details.m_sortDescription.sortOrder;
1964 ar << (int)details.m_sortDescription.sortAttributes;
1965 ar << details.m_buttonLabel;
1966 ar << details.m_labelMasks.m_strLabelFile;
1967 ar << details.m_labelMasks.m_strLabelFolder;
1968 ar << details.m_labelMasks.m_strLabel2File;
1969 ar << details.m_labelMasks.m_strLabel2Folder;
1974 for (; i < (int)m_items.size(); ++i)
1976 CFileItemPtr pItem = m_items[i];
1982 CFileItemPtr pParent;
1985 CFileItemPtr pItem=m_items[0];
1986 if (pItem->IsParentFolder())
1987 pParent.reset(new CFileItem(*pItem));
1990 SetFastLookup(false);
1994 CFileItem::Archive(ar);
2003 m_items.reserve(iSize + 1);
2004 m_items.push_back(pParent);
2007 m_items.reserve(iSize);
2009 bool fastLookup=false;
2013 ar >> (int&)tempint;
2014 m_sortDescription.sortBy = (SortBy)tempint;
2015 ar >> (int&)tempint;
2016 m_sortDescription.sortOrder = (SortOrder)tempint;
2017 ar >> (int&)tempint;
2018 m_sortDescription.sortAttributes = (SortAttribute)tempint;
2019 ar >> m_sortIgnoreFolders;
2020 ar >> (int&)tempint;
2021 m_cacheToDisc = CACHE_TYPE(tempint);
2023 unsigned int detailSize = 0;
2025 for (unsigned int j = 0; j < detailSize; ++j)
2027 SORT_METHOD_DETAILS details;
2028 ar >> (int&)tempint;
2029 details.m_sortDescription.sortBy = (SortBy)tempint;
2030 ar >> (int&)tempint;
2031 details.m_sortDescription.sortOrder = (SortOrder)tempint;
2032 ar >> (int&)tempint;
2033 details.m_sortDescription.sortAttributes = (SortAttribute)tempint;
2034 ar >> details.m_buttonLabel;
2035 ar >> details.m_labelMasks.m_strLabelFile;
2036 ar >> details.m_labelMasks.m_strLabelFolder;
2037 ar >> details.m_labelMasks.m_strLabel2File;
2038 ar >> details.m_labelMasks.m_strLabel2Folder;
2039 m_sortDetails.push_back(details);
2044 for (int i = 0; i < iSize; ++i)
2046 CFileItemPtr pItem(new CFileItem);
2051 SetFastLookup(fastLookup);
2055 void CFileItemList::FillInDefaultIcons()
2057 CSingleLock lock(m_lock);
2058 for (int i = 0; i < (int)m_items.size(); ++i)
2060 CFileItemPtr pItem = m_items[i];
2061 pItem->FillInDefaultIcon();
2065 int CFileItemList::GetFolderCount() const
2067 CSingleLock lock(m_lock);
2068 int nFolderCount = 0;
2069 for (int i = 0; i < (int)m_items.size(); i++)
2071 CFileItemPtr pItem = m_items[i];
2072 if (pItem->m_bIsFolder)
2076 return nFolderCount;
2079 int CFileItemList::GetObjectCount() const
2081 CSingleLock lock(m_lock);
2083 int numObjects = (int)m_items.size();
2084 if (numObjects && m_items[0]->IsParentFolder())
2090 int CFileItemList::GetFileCount() const
2092 CSingleLock lock(m_lock);
2094 for (int i = 0; i < (int)m_items.size(); i++)
2096 CFileItemPtr pItem = m_items[i];
2097 if (!pItem->m_bIsFolder)
2104 int CFileItemList::GetSelectedCount() const
2106 CSingleLock lock(m_lock);
2108 for (int i = 0; i < (int)m_items.size(); i++)
2110 CFileItemPtr pItem = m_items[i];
2111 if (pItem->IsSelected())
2118 void CFileItemList::FilterCueItems()
2120 CSingleLock lock(m_lock);
2121 // Handle .CUE sheet files...
2122 VECSONGS itemstoadd;
2123 CStdStringArray itemstodelete;
2124 for (int i = 0; i < (int)m_items.size(); i++)
2126 CFileItemPtr pItem = m_items[i];
2127 if (!pItem->m_bIsFolder)
2128 { // see if it's a .CUE sheet
2129 if (pItem->IsCUESheet())
2131 CCueDocument cuesheet;
2132 if (cuesheet.Parse(pItem->GetPath()))
2135 cuesheet.GetSongs(newitems);
2137 std::vector<CStdString> MediaFileVec;
2138 cuesheet.GetMediaFiles(MediaFileVec);
2140 // queue the cue sheet and the underlying media file for deletion
2141 for(std::vector<CStdString>::iterator itMedia = MediaFileVec.begin(); itMedia != MediaFileVec.end(); itMedia++)
2143 CStdString strMediaFile = *itMedia;
2144 CStdString fileFromCue = strMediaFile; // save the file from the cue we're matching against,
2145 // as we're going to search for others here...
2146 bool bFoundMediaFile = CFile::Exists(strMediaFile);
2147 // queue the cue sheet and the underlying media file for deletion
2148 if (!bFoundMediaFile)
2150 // try file in same dir, not matching case...
2151 if (Contains(strMediaFile))
2153 bFoundMediaFile = true;
2157 // try removing the .cue extension...
2158 strMediaFile = pItem->GetPath();
2159 URIUtils::RemoveExtension(strMediaFile);
2160 CFileItem item(strMediaFile, false);
2161 if (item.IsAudio() && Contains(strMediaFile))
2163 bFoundMediaFile = true;
2166 { // try replacing the extension with one of our allowed ones.
2167 CStdStringArray extensions;
2168 StringUtils::SplitString(g_advancedSettings.m_musicExtensions, "|", extensions);
2169 for (unsigned int i = 0; i < extensions.size(); i++)
2171 strMediaFile = URIUtils::ReplaceExtension(pItem->GetPath(), extensions[i]);
2172 CFileItem item(strMediaFile, false);
2173 if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile))
2175 bFoundMediaFile = true;
2182 if (bFoundMediaFile)
2184 itemstodelete.push_back(pItem->GetPath());
2185 itemstodelete.push_back(strMediaFile);
2186 // get the additional stuff (year, genre etc.) from the underlying media files tag.
2188 auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(strMediaFile));
2189 if (NULL != pLoader.get())
2192 pLoader->Load(strMediaFile, tag);
2194 // fill in any missing entries from underlying media file
2195 for (int j = 0; j < (int)newitems.size(); j++)
2197 CSong song = newitems[j];
2198 // only for songs that actually match the current media file
2199 if (song.strFileName == fileFromCue)
2201 // we might have a new media file from the above matching code
2202 song.strFileName = strMediaFile;
2205 if (song.strAlbum.empty() && !tag.GetAlbum().empty()) song.strAlbum = tag.GetAlbum();
2206 if (song.albumArtist.empty() && !tag.GetAlbumArtist().empty()) song.albumArtist = tag.GetAlbumArtist();
2207 if (song.genre.empty() && !tag.GetGenre().empty()) song.genre = tag.GetGenre();
2208 if (song.artist.empty() && !tag.GetArtist().empty()) song.artist = tag.GetArtist();
2209 if (tag.GetDiscNumber()) song.iTrack |= (tag.GetDiscNumber() << 16); // see CMusicInfoTag::GetDiscNumber()
2210 SYSTEMTIME dateTime;
2211 tag.GetReleaseDate(dateTime);
2212 if (dateTime.wYear) song.iYear = dateTime.wYear;
2213 if (song.embeddedArt.empty() && !tag.GetCoverArtInfo().empty())
2214 song.embeddedArt = tag.GetCoverArtInfo();
2216 if (!song.iDuration && tag.GetDuration() > 0)
2217 { // must be the last song
2218 song.iDuration = (tag.GetDuration() * 75 - song.iStartOffset + 37) / 75;
2220 // add this item to the list
2221 itemstoadd.push_back(song);
2226 { // remove the .cue sheet from the directory
2227 itemstodelete.push_back(pItem->GetPath());
2232 { // remove the .cue sheet from the directory (can't parse it - no point listing it)
2233 itemstodelete.push_back(pItem->GetPath());
2238 // now delete the .CUE files and underlying media files.
2239 for (int i = 0; i < (int)itemstodelete.size(); i++)
2241 for (int j = 0; j < (int)m_items.size(); j++)
2243 CFileItemPtr pItem = m_items[j];
2244 if (stricmp(pItem->GetPath().c_str(), itemstodelete[i].c_str()) == 0)
2245 { // delete this item
2246 m_items.erase(m_items.begin() + j);
2251 // and add the files from the .CUE sheet
2252 for (int i = 0; i < (int)itemstoadd.size(); i++)
2254 // now create the file item, and add to the item list.
2255 CFileItemPtr pItem(new CFileItem(itemstoadd[i]));
2256 m_items.push_back(pItem);
2260 // Remove the extensions from the filenames
2261 void CFileItemList::RemoveExtensions()
2263 CSingleLock lock(m_lock);
2264 for (int i = 0; i < Size(); ++i)
2265 m_items[i]->RemoveExtension();
2268 void CFileItemList::Stack(bool stackFiles /* = true */)
2270 CSingleLock lock(m_lock);
2273 if (IsVirtualDirectoryRoot() || IsLiveTV() || IsSourcesPath())
2276 SetProperty("isstacked", true);
2278 // items needs to be sorted for stuff below to work properly
2279 Sort(SortByLabel, SortOrderAscending);
2287 void CFileItemList::StackFolders()
2289 // Precompile our REs
2290 VECCREGEXP folderRegExps;
2291 CRegExp folderRegExp(true, true);
2292 const CStdStringArray& strFolderRegExps = g_advancedSettings.m_folderStackRegExps;
2294 CStdStringArray::const_iterator strExpression = strFolderRegExps.begin();
2295 while (strExpression != strFolderRegExps.end())
2297 if (!folderRegExp.RegComp(*strExpression))
2298 CLog::Log(LOGERROR, "%s: Invalid folder stack RegExp:'%s'", __FUNCTION__, strExpression->c_str());
2300 folderRegExps.push_back(folderRegExp);
2306 for (int i = 0; i < Size(); i++)
2308 CFileItemPtr item = Get(i);
2309 // combined the folder checks
2310 if (item->m_bIsFolder)
2312 // only check known fast sources?
2314 // 1. rars and zips may be on slow sources? is this supposed to be allowed?
2315 if( !item->IsRemote()
2319 || URIUtils::IsInRAR(item->GetPath())
2320 || URIUtils::IsInZIP(item->GetPath())
2321 || URIUtils::IsOnLAN(item->GetPath())
2324 // stack cd# folders if contains only a single video file
2328 VECCREGEXP::iterator expr = folderRegExps.begin();
2329 while (!bMatch && expr != folderRegExps.end())
2331 //CLog::Log(LOGDEBUG,"%s: Running expression %s on %s", __FUNCTION__, expr->GetPattern().c_str(), item->GetLabel().c_str());
2332 bMatch = (expr->RegFind(item->GetLabel().c_str()) != -1);
2335 CFileItemList items;
2336 CDirectory::GetDirectory(item->GetPath(),items,g_advancedSettings.m_videoExtensions);
2337 // optimized to only traverse listing once by checking for filecount
2338 // and recording last file item for later use
2341 for (int j = 0; j < items.Size(); j++)
2343 if (!items[j]->m_bIsFolder)
2354 *item = *items[index];
2359 // check for dvd folders
2364 path = URIUtils::AddFileToFolder(item->GetPath(), "VIDEO_TS.IFO");
2365 if (CFile::Exists(path))
2369 dvdPath = URIUtils::AddFileToFolder(item->GetPath(), "VIDEO_TS");
2370 path = URIUtils::AddFileToFolder(dvdPath, "VIDEO_TS.IFO");
2372 if (CFile::Exists(path))
2375 #ifdef HAVE_LIBBLURAY
2376 if (dvdPath.empty())
2378 path = URIUtils::AddFileToFolder(item->GetPath(), "index.bdmv");
2379 if (CFile::Exists(path))
2383 dvdPath = URIUtils::AddFileToFolder(item->GetPath(), "BDMV");
2384 path = URIUtils::AddFileToFolder(dvdPath, "index.bdmv");
2386 if (CFile::Exists(path))
2391 if (!dvdPath.empty())
2393 // NOTE: should this be done for the CD# folders too?
2394 item->m_bIsFolder = false;
2395 item->SetPath(dvdPath);
2396 item->SetLabel2("");
2397 item->SetLabelPreformated(true);
2398 m_sortDescription.sortBy = SortByNone; /* sorting is now broken */
2406 void CFileItemList::StackFiles()
2408 // Precompile our REs
2409 VECCREGEXP stackRegExps;
2410 CRegExp tmpRegExp(true, true);
2411 const CStdStringArray& strStackRegExps = g_advancedSettings.m_videoStackRegExps;
2412 CStdStringArray::const_iterator strRegExp = strStackRegExps.begin();
2413 while (strRegExp != strStackRegExps.end())
2415 if (tmpRegExp.RegComp(*strRegExp))
2417 if (tmpRegExp.GetCaptureTotal() == 4)
2418 stackRegExps.push_back(tmpRegExp);
2420 CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have 4 captures.", strRegExp->c_str());
2425 // now stack the files, some of which may be from the previous stack iteration
2429 CFileItemPtr item1 = Get(i);
2431 // skip folders, nfo files, playlists
2432 if (item1->m_bIsFolder
2433 || item1->IsParentFolder()
2435 || item1->IsPlayList()
2445 CStdString stackName;
2447 CStdString filePath;
2449 VECCREGEXP::iterator expr = stackRegExps.begin();
2451 URIUtils::Split(item1->GetPath(), filePath, file1);
2452 if (URIUtils::ProtocolHasEncodedFilename(CURL(filePath).GetProtocol() ) )
2453 CURL::Decode(file1);
2456 while (expr != stackRegExps.end())
2458 if (expr->RegFind(file1, offset) != -1)
2460 CStdString Title1 = expr->GetMatch(1),
2461 Volume1 = expr->GetMatch(2),
2462 Ignore1 = expr->GetMatch(3),
2463 Extension1 = expr->GetMatch(4);
2465 Title1 = file1.substr(0, expr->GetSubStart(2));
2469 CFileItemPtr item2 = Get(j);
2471 // skip folders, nfo files, playlists
2472 if (item2->m_bIsFolder
2473 || item2->IsParentFolder()
2475 || item2->IsPlayList()
2483 CStdString file2, filePath2;
2484 URIUtils::Split(item2->GetPath(), filePath2, file2);
2485 if (URIUtils::ProtocolHasEncodedFilename(CURL(filePath2).GetProtocol() ) )
2486 CURL::Decode(file2);
2488 if (expr->RegFind(file2, offset) != -1)
2490 CStdString Title2 = expr->GetMatch(1),
2491 Volume2 = expr->GetMatch(2),
2492 Ignore2 = expr->GetMatch(3),
2493 Extension2 = expr->GetMatch(4);
2495 Title2 = file2.substr(0, expr->GetSubStart(2));
2496 if (Title1.Equals(Title2))
2498 if (!Volume1.Equals(Volume2))
2500 if (Ignore1.Equals(Ignore2) && Extension1.Equals(Extension2))
2502 if (stack.size() == 0)
2504 stackName = Title1 + Ignore1 + Extension1;
2506 size += item1->m_dwSize;
2509 size += item2->m_dwSize;
2518 else if (!Ignore1.Equals(Ignore2)) // False positive, try again with offset
2520 offset = expr->GetSubStart(3);
2523 else // Extension mismatch
2530 else // Title mismatch
2537 else // No match 2, next expression
2546 expr = stackRegExps.end();
2553 if (stack.size() > 1)
2555 // have a stack, remove the items and add the stacked item
2556 // dont actually stack a multipart rar set, just remove all items but the first
2557 CStdString stackPath;
2558 if (Get(stack[0])->IsRAR())
2559 stackPath = Get(stack[0])->GetPath();
2562 CStackDirectory dir;
2563 stackPath = dir.ConstructStackPath(*this, stack);
2565 item1->SetPath(stackPath);
2567 for (unsigned k = 1; k < stack.size(); k++)
2569 // item->m_bIsFolder = true; // don't treat stacked files as folders
2570 // the label may be in a different char set from the filename (eg over smb
2571 // the label is converted from utf8, but the filename is not)
2572 if (!CSettings::Get().GetBool("filelists.showextensions"))
2573 URIUtils::RemoveExtension(stackName);
2575 item1->SetLabel(stackName);
2576 item1->m_dwSize = size;
2584 bool CFileItemList::Load(int windowID)
2587 if (file.Open(GetDiscFileCache(windowID)))
2589 CArchive ar(&file, CArchive::load);
2591 CLog::Log(LOGDEBUG,"Loading items: %i, directory: %s sort method: %i, ascending: %s", Size(), CURL::GetRedacted(GetPath()).c_str(), m_sortDescription.sortBy,
2592 m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false");
2601 bool CFileItemList::Save(int windowID)
2607 CLog::Log(LOGDEBUG,"Saving fileitems [%s]", CURL::GetRedacted(GetPath()).c_str());
2610 if (file.OpenForWrite(GetDiscFileCache(windowID), true)) // overwrite always
2612 CArchive ar(&file, CArchive::store);
2614 CLog::Log(LOGDEBUG," -- items: %i, sort method: %i, ascending: %s", iSize, m_sortDescription.sortBy, m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false");
2623 void CFileItemList::RemoveDiscCache(int windowID) const
2625 CStdString cacheFile(GetDiscFileCache(windowID));
2626 if (CFile::Exists(cacheFile))
2628 CLog::Log(LOGDEBUG,"Clearing cached fileitems [%s]",GetPath().c_str());
2629 CFile::Delete(cacheFile);
2633 CStdString CFileItemList::GetDiscFileCache(int windowID) const
2635 CStdString strPath(GetPath());
2636 URIUtils::RemoveSlashAtEnd(strPath);
2639 crc.ComputeFromLowerCase(strPath);
2641 CStdString cacheFile;
2642 if (IsCDDA() || IsOnDVD())
2643 cacheFile = StringUtils::Format("special://temp/r-%08x.fi", (unsigned __int32)crc);
2644 else if (IsMusicDb())
2645 cacheFile = StringUtils::Format("special://temp/mdb-%08x.fi", (unsigned __int32)crc);
2646 else if (IsVideoDb())
2647 cacheFile = StringUtils::Format("special://temp/vdb-%08x.fi", (unsigned __int32)crc);
2648 else if (IsSmartPlayList())
2649 cacheFile = StringUtils::Format("special://temp/sp-%08x.fi", (unsigned __int32)crc);
2651 cacheFile = StringUtils::Format("special://temp/%i-%08x.fi", windowID, (unsigned __int32)crc);
2653 cacheFile = StringUtils::Format("special://temp/%08x.fi", (unsigned __int32)crc);
2657 bool CFileItemList::AlwaysCache() const
2659 // some database folders are always cached
2661 return CMusicDatabaseDirectory::CanCache(GetPath());
2663 return CVideoDatabaseDirectory::CanCache(GetPath());
2665 return true; // always cache
2669 CStdString CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */, bool fallbackToFolder /* = false */) const
2671 if (m_strPath.empty()
2672 || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://")
2673 || StringUtils::StartsWithNoCase(m_strPath, "newplaylist://")
2674 || m_bIsShareOrDrive
2675 || IsInternetStream()
2676 || URIUtils::IsUPnP(m_strPath)
2677 || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
2684 // we first check for <filename>.tbn or <foldername>.tbn
2685 CStdString fileThumb(GetTBNFile());
2686 if (CFile::Exists(fileThumb))
2689 // Fall back to folder thumb, if requested
2690 if (!m_bIsFolder && fallbackToFolder)
2692 CFileItem item(URIUtils::GetDirectory(m_strPath), true);
2693 return item.GetUserMusicThumb(alwaysCheckRemote);
2696 // if a folder, check for folder.jpg
2697 if (m_bIsFolder && !IsFileFolder() && (!IsRemote() || alwaysCheckRemote || CSettings::Get().GetBool("musicfiles.findremotethumbs")))
2699 CStdStringArray thumbs;
2700 StringUtils::SplitString(g_advancedSettings.m_musicThumbs, "|", thumbs);
2701 for (unsigned int i = 0; i < thumbs.size(); ++i)
2703 CStdString folderThumb(GetFolderThumb(thumbs[i]));
2704 if (CFile::Exists(folderThumb))
2714 // Gets the .tbn filename from a file or folder name.
2715 // <filename>.ext -> <filename>.tbn
2716 // <foldername>/ -> <foldername>.tbn
2717 CStdString CFileItem::GetTBNFile() const
2719 CStdString thumbFile;
2720 CStdString strFile = m_strPath;
2724 CStdString strPath, strReturn;
2725 URIUtils::GetParentPath(m_strPath,strPath);
2726 CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2727 CStdString strTBNFile = item.GetTBNFile();
2728 strReturn = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strTBNFile));
2729 if (CFile::Exists(strReturn))
2732 strFile = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)));
2735 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2737 CStdString strPath = URIUtils::GetDirectory(strFile);
2738 CStdString strParent;
2739 URIUtils::GetParentPath(strPath,strParent);
2740 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(m_strPath));
2744 strFile = url.GetFileName();
2746 if (m_bIsFolder && !IsFileFolder())
2747 URIUtils::RemoveSlashAtEnd(strFile);
2749 if (!strFile.empty())
2751 if (m_bIsFolder && !IsFileFolder())
2752 thumbFile = strFile + ".tbn"; // folder, so just add ".tbn"
2754 thumbFile = URIUtils::ReplaceExtension(strFile, ".tbn");
2755 url.SetFileName(thumbFile);
2756 thumbFile = url.Get();
2761 CStdString CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) const
2763 // ignore a bunch that are meaningless
2764 if (m_strPath.empty()
2765 || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://")
2766 || StringUtils::StartsWithNoCase(m_strPath, "newplaylist://")
2767 || m_bIsShareOrDrive
2768 || IsInternetStream()
2769 || URIUtils::IsUPnP(m_strPath)
2770 || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
2781 thumb = GetLocalArt(artFile, false);
2782 if (!thumb.empty() && CFile::Exists(thumb))
2785 if ((useFolder || (m_bIsFolder && !IsFileFolder())) && !artFile.empty())
2787 CStdString thumb2 = GetLocalArt(artFile, true);
2788 if (!thumb2.empty() && thumb2 != thumb && CFile::Exists(thumb2))
2794 CStdString CFileItem::GetLocalArt(const std::string &artFile, bool useFolder) const
2796 // no retrieving of empty art files from folders
2797 if (useFolder && artFile.empty())
2800 CStdString strFile = m_strPath;
2803 /* CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2804 CStdString localArt = item.GetLocalArt(artFile);
2808 URIUtils::GetParentPath(m_strPath,strPath);
2809 strFile = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)));
2812 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2814 CStdString strPath = URIUtils::GetDirectory(strFile);
2815 CStdString strParent;
2816 URIUtils::GetParentPath(strPath,strParent);
2817 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(strFile));
2821 strFile = CMultiPathDirectory::GetFirstPath(m_strPath);
2823 if (IsOpticalMediaFile())
2824 { // optical media files should be treated like folders
2826 strFile = GetLocalMetadataPath();
2828 else if (useFolder && !(m_bIsFolder && !IsFileFolder()))
2829 strFile = URIUtils::GetDirectory(strFile);
2831 if (strFile.empty()) // empty filepath -> nothing to find
2836 if (!artFile.empty())
2837 return URIUtils::AddFileToFolder(strFile, artFile);
2841 if (artFile.empty()) // old thumbnail matching
2842 return URIUtils::ReplaceExtension(strFile, ".tbn");
2844 return URIUtils::ReplaceExtension(strFile, "-" + artFile);
2849 CStdString CFileItem::GetFolderThumb(const CStdString &folderJPG /* = "folder.jpg" */) const
2851 CStdString strFolder = m_strPath;
2854 URIUtils::IsInRAR(strFolder) ||
2855 URIUtils::IsInZIP(strFolder))
2857 URIUtils::GetParentPath(m_strPath,strFolder);
2861 strFolder = CMultiPathDirectory::GetFirstPath(m_strPath);
2863 return URIUtils::AddFileToFolder(strFolder, folderJPG);
2866 CStdString CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const
2868 if (IsLabelPreformated())
2871 if (m_pvrRecordingInfoTag)
2872 return m_pvrRecordingInfoTag->m_strTitle;
2873 else if (CUtil::IsTVRecording(m_strPath))
2875 CStdString title = CPVRRecording::GetTitleFromURL(m_strPath);
2880 CStdString strMovieName = GetBaseMoviePath(bUseFolderNames);
2882 if (URIUtils::IsStack(strMovieName))
2883 strMovieName = CStackDirectory::GetStackedTitlePath(strMovieName);
2885 URIUtils::RemoveSlashAtEnd(strMovieName);
2886 strMovieName = URIUtils::GetFileName(strMovieName);
2887 CURL::Decode(strMovieName);
2889 return strMovieName;
2892 CStdString CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
2894 CStdString strMovieName = m_strPath;
2897 strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
2899 if (IsOpticalMediaFile())
2900 return GetLocalMetadataPath();
2902 if ((!m_bIsFolder || URIUtils::IsInArchive(m_strPath)) && bUseFolderNames)
2904 CStdString name2(strMovieName);
2905 URIUtils::GetParentPath(name2,strMovieName);
2906 if (URIUtils::IsInArchive(m_strPath))
2908 CStdString strArchivePath;
2909 URIUtils::GetParentPath(strMovieName, strArchivePath);
2910 strMovieName = strArchivePath;
2914 return strMovieName;
2917 CStdString CFileItem::GetLocalFanart() const
2921 if (!HasVideoInfoTag())
2922 return ""; // nothing can be done
2923 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
2924 return dbItem.GetLocalFanart();
2927 CStdString strFile2;
2928 CStdString strFile = m_strPath;
2932 URIUtils::GetParentPath(m_strPath,strPath);
2933 CStackDirectory dir;
2934 CStdString strPath2;
2935 strPath2 = dir.GetStackedTitlePath(strFile);
2936 strFile = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strPath2));
2937 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
2938 CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-fanart"));
2939 strFile2 = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strTBNFile));
2941 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2943 CStdString strPath = URIUtils::GetDirectory(strFile);
2944 CStdString strParent;
2945 URIUtils::GetParentPath(strPath,strParent);
2946 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(m_strPath));
2949 // no local fanart available for these
2950 if (IsInternetStream()
2951 || URIUtils::IsUPnP(strFile)
2952 || URIUtils::IsBluray(strFile)
2957 || (URIUtils::IsFTP(strFile) && !g_advancedSettings.m_bFTPThumbs)
2958 || m_strPath.empty())
2961 CStdString strDir = URIUtils::GetDirectory(strFile);
2966 CFileItemList items;
2967 CDirectory::GetDirectory(strDir, items, g_advancedSettings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
2968 if (IsOpticalMediaFile())
2969 { // grab from the optical media parent folder as well
2970 CFileItemList moreItems;
2971 CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems, g_advancedSettings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
2972 items.Append(moreItems);
2975 CStdStringArray fanarts;
2976 StringUtils::SplitString(g_advancedSettings.m_fanartImages, "|", fanarts);
2978 strFile = URIUtils::ReplaceExtension(strFile, "-fanart");
2979 fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile));
2981 if (!strFile2.empty())
2982 fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile2));
2984 for (unsigned int i = 0; i < fanarts.size(); ++i)
2986 for (int j = 0; j < items.Size(); j++)
2988 CStdString strCandidate = URIUtils::GetFileName(items[j]->m_strPath);
2989 URIUtils::RemoveExtension(strCandidate);
2990 CStdString strFanart = fanarts[i];
2991 URIUtils::RemoveExtension(strFanart);
2992 if (strCandidate.CompareNoCase(strFanart) == 0)
2993 return items[j]->m_strPath;
3000 CStdString CFileItem::GetLocalMetadataPath() const
3002 if (m_bIsFolder && !IsFileFolder())
3005 CStdString parent(URIUtils::GetParentPath(m_strPath));
3006 CStdString parentFolder(parent);
3007 URIUtils::RemoveSlashAtEnd(parentFolder);
3008 parentFolder = URIUtils::GetFileName(parentFolder);
3009 if (parentFolder.CompareNoCase("VIDEO_TS") == 0 || parentFolder.CompareNoCase("BDMV") == 0)
3010 { // go back up another one
3011 parent = URIUtils::GetParentPath(parent);
3016 bool CFileItem::LoadMusicTag()
3022 if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
3025 CMusicDatabase musicDatabase;
3026 if (musicDatabase.Open())
3029 if (musicDatabase.GetSongByFileName(m_strPath, song))
3031 GetMusicInfoTag()->SetSong(song);
3032 SetArt("thumb", song.strThumb);
3035 musicDatabase.Close();
3037 // load tag from file
3038 CLog::Log(LOGDEBUG, "%s: loading tag information for file: %s", __FUNCTION__, m_strPath.c_str());
3039 CMusicInfoTagLoaderFactory factory;
3040 auto_ptr<IMusicInfoTagLoader> pLoader (factory.CreateLoader(m_strPath));
3041 if (NULL != pLoader.get())
3043 if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
3046 // no tag - try some other things
3049 // we have the tracknumber...
3050 int iTrack = GetMusicInfoTag()->GetTrackNumber();
3053 CStdString strText = g_localizeStrings.Get(554); // "Track"
3054 if (strText.GetAt(strText.size() - 1) != ' ')
3056 CStdString strTrack = StringUtils::Format(strText + "%i", iTrack);
3057 GetMusicInfoTag()->SetTitle(strTrack);
3058 GetMusicInfoTag()->SetLoaded(true);
3064 CStdString fileName = URIUtils::GetFileName(m_strPath);
3065 URIUtils::RemoveExtension(fileName);
3066 for (unsigned int i = 0; i < g_advancedSettings.m_musicTagsFromFileFilters.size(); i++)
3068 CLabelFormatter formatter(g_advancedSettings.m_musicTagsFromFileFilters[i], "");
3069 if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
3071 GetMusicInfoTag()->SetLoaded(true);
3079 void CFileItemList::Swap(unsigned int item1, unsigned int item2)
3081 if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size())
3082 std::swap(m_items[item1], m_items[item2]);
3085 bool CFileItemList::UpdateItem(const CFileItem *item)
3087 if (!item) return false;
3089 CSingleLock lock(m_lock);
3090 for (unsigned int i = 0; i < m_items.size(); i++)
3092 CFileItemPtr pItem = m_items[i];
3093 if (pItem->IsSamePath(item))
3095 pItem->UpdateInfo(*item);
3102 void CFileItemList::AddSortMethod(SortBy sortBy, int buttonLabel, const LABEL_MASKS &labelMasks, SortAttribute sortAttributes /* = SortAttributeNone */)
3104 AddSortMethod(sortBy, sortAttributes, buttonLabel, labelMasks);
3107 void CFileItemList::AddSortMethod(SortBy sortBy, SortAttribute sortAttributes, int buttonLabel, const LABEL_MASKS &labelMasks)
3109 SortDescription sorting;
3110 sorting.sortBy = sortBy;
3111 sorting.sortAttributes = sortAttributes;
3113 AddSortMethod(sorting, buttonLabel, labelMasks);
3116 void CFileItemList::AddSortMethod(SortDescription sortDescription, int buttonLabel, const LABEL_MASKS &labelMasks)
3118 SORT_METHOD_DETAILS sort;
3119 sort.m_sortDescription = sortDescription;
3120 sort.m_buttonLabel = buttonLabel;
3121 sort.m_labelMasks = labelMasks;
3123 m_sortDetails.push_back(sort);
3126 void CFileItemList::SetReplaceListing(bool replace)
3128 m_replaceListing = replace;
3131 void CFileItemList::ClearSortState()
3133 m_sortDescription.sortBy = SortByNone;
3134 m_sortDescription.sortOrder = SortOrderNone;
3135 m_sortDescription.sortAttributes = SortAttributeNone;
3138 CVideoInfoTag* CFileItem::GetVideoInfoTag()
3140 if (!m_videoInfoTag)
3141 m_videoInfoTag = new CVideoInfoTag;
3143 return m_videoInfoTag;
3146 CEpgInfoTag* CFileItem::GetEPGInfoTag()
3149 m_epgInfoTag = new CEpgInfoTag;
3151 return m_epgInfoTag;
3154 CPVRChannel* CFileItem::GetPVRChannelInfoTag()
3156 if (!m_pvrChannelInfoTag)
3157 m_pvrChannelInfoTag = new CPVRChannel;
3159 return m_pvrChannelInfoTag;
3162 CPVRRecording* CFileItem::GetPVRRecordingInfoTag()
3164 if (!m_pvrRecordingInfoTag)
3165 m_pvrRecordingInfoTag = new CPVRRecording;
3167 return m_pvrRecordingInfoTag;
3170 CPVRTimerInfoTag* CFileItem::GetPVRTimerInfoTag()
3172 if (!m_pvrTimerInfoTag)
3173 m_pvrTimerInfoTag = new CPVRTimerInfoTag;
3175 return m_pvrTimerInfoTag;
3178 CPictureInfoTag* CFileItem::GetPictureInfoTag()
3180 if (!m_pictureInfoTag)
3181 m_pictureInfoTag = new CPictureInfoTag;
3183 return m_pictureInfoTag;
3186 MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
3188 if (!m_musicInfoTag)
3189 m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
3191 return m_musicInfoTag;
3194 CStdString CFileItem::FindTrailer() const
3196 CStdString strFile2;
3197 CStdString strFile = m_strPath;
3201 URIUtils::GetParentPath(m_strPath,strPath);
3202 CStackDirectory dir;
3203 CStdString strPath2;
3204 strPath2 = dir.GetStackedTitlePath(strFile);
3205 strFile = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2));
3206 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
3207 CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-trailer"));
3208 strFile2 = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile));
3210 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
3212 CStdString strPath = URIUtils::GetDirectory(strFile);
3213 CStdString strParent;
3214 URIUtils::GetParentPath(strPath,strParent);
3215 strFile = URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath));
3218 // no local trailer available for these
3219 if (IsInternetStream()
3220 || URIUtils::IsUPnP(strFile)
3221 || URIUtils::IsBluray(strFile)
3227 CStdString strDir = URIUtils::GetDirectory(strFile);
3228 CFileItemList items;
3229 CDirectory::GetDirectory(strDir, items, g_advancedSettings.m_videoExtensions, DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
3230 URIUtils::RemoveExtension(strFile);
3231 strFile += "-trailer";
3232 CStdString strFile3 = URIUtils::AddFileToFolder(strDir, "movie-trailer");
3234 // Precompile our REs
3235 VECCREGEXP matchRegExps;
3236 CRegExp tmpRegExp(true, true);
3237 const CStdStringArray& strMatchRegExps = g_advancedSettings.m_trailerMatchRegExps;
3239 CStdStringArray::const_iterator strRegExp = strMatchRegExps.begin();
3240 while (strRegExp != strMatchRegExps.end())
3242 if (tmpRegExp.RegComp(*strRegExp))
3244 matchRegExps.push_back(tmpRegExp);
3249 CStdString strTrailer;
3250 for (int i = 0; i < items.Size(); i++)
3252 CStdString strCandidate = items[i]->m_strPath;
3253 URIUtils::RemoveExtension(strCandidate);
3254 if (strCandidate.CompareNoCase(strFile) == 0 ||
3255 strCandidate.CompareNoCase(strFile2) == 0 ||
3256 strCandidate.CompareNoCase(strFile3) == 0)
3258 strTrailer = items[i]->m_strPath;
3263 VECCREGEXP::iterator expr = matchRegExps.begin();
3265 while (expr != matchRegExps.end())
3267 if (expr->RegFind(strCandidate) != -1)
3269 strTrailer = items[i]->m_strPath;
3281 int CFileItem::GetVideoContentType() const
3283 VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
3284 if (HasVideoInfoTag() && !GetVideoInfoTag()->m_strShowTitle.empty()) // tvshow
3285 type = VIDEODB_CONTENT_TVSHOWS;
3286 if (HasVideoInfoTag() && GetVideoInfoTag()->m_iSeason > -1 && !m_bIsFolder) // episode
3287 return VIDEODB_CONTENT_EPISODES;
3288 if (HasVideoInfoTag() && !GetVideoInfoTag()->m_artist.empty()) // music video
3289 return VIDEODB_CONTENT_MUSICVIDEOS;
3291 CVideoDatabaseDirectory dir;
3292 VIDEODATABASEDIRECTORY::CQueryParams params;
3293 dir.GetQueryParams(m_strPath, params);
3294 if (params.GetSetId() != -1 && params.GetMovieId() == -1) // movie set
3295 return VIDEODB_CONTENT_MOVIE_SETS;