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"
25 #include "utils/Archive.h"
27 #include "playlists/PlayListFactory.h"
28 #include "utils/Crc32.h"
29 #include "filesystem/Directory.h"
30 #include "filesystem/StackDirectory.h"
31 #include "filesystem/CurlFile.h"
32 #include "filesystem/MultiPathDirectory.h"
33 #include "filesystem/MusicDatabaseDirectory.h"
34 #include "filesystem/VideoDatabaseDirectory.h"
35 #include "filesystem/VideoDatabaseDirectory/QueryParams.h"
36 #include "music/tags/MusicInfoTagLoaderFactory.h"
37 #include "CueDocument.h"
38 #include "video/VideoDatabase.h"
39 #include "music/MusicDatabase.h"
40 #include "utils/TuxBoxUtil.h"
42 #include "pvr/channels/PVRChannel.h"
43 #include "pvr/recordings/PVRRecording.h"
44 #include "pvr/timers/PVRTimerInfoTag.h"
45 #include "utils/Observer.h"
46 #include "video/VideoInfoTag.h"
47 #include "threads/SingleLock.h"
48 #include "music/tags/MusicInfoTag.h"
49 #include "pictures/PictureInfoTag.h"
50 #include "music/Artist.h"
51 #include "music/Album.h"
52 #include "music/Song.h"
54 #include "settings/AdvancedSettings.h"
55 #include "settings/Settings.h"
56 #include "utils/RegExp.h"
57 #include "utils/log.h"
58 #include "utils/Variant.h"
59 #include "music/karaoke/karaokelyricsfactory.h"
60 #include "utils/Mime.h"
62 #include "cores/paplayer/ASAPCodec.h"
66 using namespace XFILE;
67 using namespace PLAYLIST;
68 using namespace MUSIC_INFO;
72 CFileItem::CFileItem(const CSong& song)
78 CFileItem::CFileItem(const CURL &url, const CAlbum& album)
82 m_strPath = url.Get();
83 URIUtils::AddSlashAtEnd(m_strPath);
87 CFileItem::CFileItem(const std::string &path, const CAlbum& album)
92 URIUtils::AddSlashAtEnd(m_strPath);
96 CFileItem::CFileItem(const CMusicInfoTag& music)
99 SetLabel(music.GetTitle());
100 m_strPath = music.GetURL();
101 m_bIsFolder = URIUtils::HasSlashAtEnd(m_strPath);
102 *GetMusicInfoTag() = music;
104 FillInMimeType(false);
107 CFileItem::CFileItem(const CVideoInfoTag& movie)
110 SetFromVideoInfoTag(movie);
113 CFileItem::CFileItem(const CEpgInfoTag& tag)
117 m_strPath = tag.Path();
119 *GetEPGInfoTag() = tag;
120 SetLabel(tag.Title());
121 m_strLabel2 = tag.Plot();
122 m_dateTime = tag.StartAsLocalTime();
124 if (!tag.Icon().empty())
125 SetIconImage(tag.Icon());
126 else if (tag.HasPVRChannel() && !tag.ChannelTag()->IconPath().empty())
127 SetIconImage(tag.ChannelTag()->IconPath());
129 FillInMimeType(false);
132 CFileItem::CFileItem(const CPVRChannel& channel)
137 bool bHasEpgNow = channel.GetEPGNow(epgNow);
139 m_strPath = channel.Path();
141 *GetPVRChannelInfoTag() = channel;
142 SetLabel(channel.ChannelName());
143 m_strLabel2 = bHasEpgNow ? epgNow.Title() :
144 CSettings::Get().GetBool("epg.hidenoinfoavailable") ?
145 "" : g_localizeStrings.Get(19055); // no information available
147 if (channel.IsRadio())
149 CMusicInfoTag* musictag = GetMusicInfoTag();
152 musictag->SetURL(channel.Path());
153 musictag->SetTitle(m_strLabel2);
154 musictag->SetArtist(channel.ChannelName());
155 musictag->SetAlbumArtist(channel.ChannelName());
157 musictag->SetGenre(epgNow.Genre());
158 musictag->SetDuration(bHasEpgNow ? epgNow.GetDuration() : 3600);
159 musictag->SetLoaded(true);
160 musictag->SetComment("");
161 musictag->SetLyrics("");
165 if (!channel.IconPath().empty())
166 SetIconImage(channel.IconPath());
168 SetProperty("channelid", channel.ChannelID());
169 SetProperty("path", channel.Path());
170 SetArt("thumb", channel.IconPath());
172 FillInMimeType(false);
175 CFileItem::CFileItem(const CPVRRecording& record)
179 m_strPath = record.m_strFileNameAndPath;
181 *GetPVRRecordingInfoTag() = record;
182 SetLabel(record.m_strTitle);
183 m_strLabel2 = record.m_strPlot;
185 FillInMimeType(false);
188 CFileItem::CFileItem(const CPVRTimerInfoTag& timer)
192 m_strPath = timer.Path();
194 *GetPVRTimerInfoTag() = timer;
195 SetLabel(timer.Title());
196 m_strLabel2 = timer.Summary();
197 m_dateTime = timer.StartAsLocalTime();
199 if (!timer.ChannelIcon().empty())
200 SetIconImage(timer.ChannelIcon());
202 FillInMimeType(false);
205 CFileItem::CFileItem(const CArtist& artist)
208 SetLabel(artist.strArtist);
209 m_strPath = artist.strArtist;
211 URIUtils::AddSlashAtEnd(m_strPath);
212 GetMusicInfoTag()->SetArtist(artist.strArtist);
213 FillInMimeType(false);
216 CFileItem::CFileItem(const CGenre& genre)
219 SetLabel(genre.strGenre);
220 m_strPath = genre.strGenre;
222 URIUtils::AddSlashAtEnd(m_strPath);
223 GetMusicInfoTag()->SetGenre(genre.strGenre);
224 FillInMimeType(false);
227 CFileItem::CFileItem(const CFileItem& item): CGUIListItem()
229 m_musicInfoTag = NULL;
230 m_videoInfoTag = NULL;
232 m_pvrChannelInfoTag = NULL;
233 m_pvrRecordingInfoTag = NULL;
234 m_pvrTimerInfoTag = NULL;
235 m_pictureInfoTag = NULL;
239 CFileItem::CFileItem(const CGUIListItem& item)
242 // not particularly pretty, but it gets around the issue of Initialize() defaulting
243 // parameters in the CGUIListItem base class.
244 *((CGUIListItem *)this) = item;
246 FillInMimeType(false);
249 CFileItem::CFileItem(void)
254 CFileItem::CFileItem(const std::string& strLabel)
261 CFileItem::CFileItem(const CURL& path, bool bIsFolder)
264 m_strPath = path.Get();
265 m_bIsFolder = bIsFolder;
266 // tuxbox urls cannot have a / at end
267 if (m_bIsFolder && !m_strPath.empty() && !IsFileFolder() && !URIUtils::IsTuxBox(m_strPath))
268 URIUtils::AddSlashAtEnd(m_strPath);
269 FillInMimeType(false);
272 CFileItem::CFileItem(const std::string& strPath, bool bIsFolder)
276 m_bIsFolder = bIsFolder;
277 // tuxbox urls cannot have a / at end
278 if (m_bIsFolder && !m_strPath.empty() && !IsFileFolder() && !URIUtils::IsTuxBox(m_strPath))
279 URIUtils::AddSlashAtEnd(m_strPath);
280 FillInMimeType(false);
283 CFileItem::CFileItem(const CMediaSource& share)
287 m_bIsShareOrDrive = true;
288 m_strPath = share.strPath;
289 if (!IsRSS()) // no slash at end for rss feeds
290 URIUtils::AddSlashAtEnd(m_strPath);
291 std::string label = share.strName;
292 if (!share.strStatus.empty())
293 label = StringUtils::Format("%s (%s)", share.strName.c_str(), share.strStatus.c_str());
295 m_iLockMode = share.m_iLockMode;
296 m_strLockCode = share.m_strLockCode;
297 m_iHasLock = share.m_iHasLock;
298 m_iBadPwdCount = share.m_iBadPwdCount;
299 m_iDriveType = share.m_iDriveType;
300 SetArt("thumb", share.m_strThumbnailImage);
301 SetLabelPreformated(true);
303 GetVideoInfoTag()->m_strFileNameAndPath = share.strDiskUniqueId; // share.strDiskUniqueId contains disc unique id
304 FillInMimeType(false);
307 CFileItem::~CFileItem(void)
309 delete m_musicInfoTag;
310 delete m_videoInfoTag;
312 delete m_pvrChannelInfoTag;
313 delete m_pvrRecordingInfoTag;
314 delete m_pvrTimerInfoTag;
315 delete m_pictureInfoTag;
317 m_musicInfoTag = NULL;
318 m_videoInfoTag = NULL;
320 m_pvrChannelInfoTag = NULL;
321 m_pvrRecordingInfoTag = NULL;
322 m_pvrTimerInfoTag = NULL;
323 m_pictureInfoTag = NULL;
326 const CFileItem& CFileItem::operator=(const CFileItem& item)
328 if (this == &item) return * this;
329 CGUIListItem::operator=(item);
330 m_bLabelPreformated=item.m_bLabelPreformated;
332 m_strPath = item.GetPath();
333 m_bIsParentFolder = item.m_bIsParentFolder;
334 m_iDriveType = item.m_iDriveType;
335 m_bIsShareOrDrive = item.m_bIsShareOrDrive;
336 m_dateTime = item.m_dateTime;
337 m_dwSize = item.m_dwSize;
338 if (item.HasMusicInfoTag())
340 m_musicInfoTag = GetMusicInfoTag();
342 *m_musicInfoTag = *item.m_musicInfoTag;
346 delete m_musicInfoTag;
347 m_musicInfoTag = NULL;
350 if (item.HasVideoInfoTag())
352 m_videoInfoTag = GetVideoInfoTag();
354 *m_videoInfoTag = *item.m_videoInfoTag;
358 delete m_videoInfoTag;
359 m_videoInfoTag = NULL;
362 if (item.HasEPGInfoTag())
364 m_epgInfoTag = GetEPGInfoTag();
366 *m_epgInfoTag = *item.m_epgInfoTag;
376 if (item.HasPVRChannelInfoTag())
378 m_pvrChannelInfoTag = GetPVRChannelInfoTag();
379 if (m_pvrChannelInfoTag)
380 *m_pvrChannelInfoTag = *item.m_pvrChannelInfoTag;
384 if (m_pvrChannelInfoTag)
385 delete m_pvrChannelInfoTag;
387 m_pvrChannelInfoTag = NULL;
390 if (item.HasPVRRecordingInfoTag())
392 m_pvrRecordingInfoTag = GetPVRRecordingInfoTag();
393 if (m_pvrRecordingInfoTag)
394 *m_pvrRecordingInfoTag = *item.m_pvrRecordingInfoTag;
398 if (m_pvrRecordingInfoTag)
399 delete m_pvrRecordingInfoTag;
401 m_pvrRecordingInfoTag = NULL;
404 if (item.HasPVRTimerInfoTag())
406 m_pvrTimerInfoTag = GetPVRTimerInfoTag();
407 if (m_pvrTimerInfoTag)
408 *m_pvrTimerInfoTag = *item.m_pvrTimerInfoTag;
412 if (m_pvrTimerInfoTag)
413 delete m_pvrTimerInfoTag;
415 m_pvrTimerInfoTag = NULL;
418 if (item.HasPictureInfoTag())
420 m_pictureInfoTag = GetPictureInfoTag();
421 if (m_pictureInfoTag)
422 *m_pictureInfoTag = *item.m_pictureInfoTag;
426 delete m_pictureInfoTag;
427 m_pictureInfoTag = NULL;
430 m_lStartOffset = item.m_lStartOffset;
431 m_lStartPartNumber = item.m_lStartPartNumber;
432 m_lEndOffset = item.m_lEndOffset;
433 m_strDVDLabel = item.m_strDVDLabel;
434 m_strTitle = item.m_strTitle;
435 m_iprogramCount = item.m_iprogramCount;
436 m_idepth = item.m_idepth;
437 m_iLockMode = item.m_iLockMode;
438 m_strLockCode = item.m_strLockCode;
439 m_iHasLock = item.m_iHasLock;
440 m_iBadPwdCount = item.m_iBadPwdCount;
441 m_bCanQueue=item.m_bCanQueue;
442 m_mimetype = item.m_mimetype;
443 m_extrainfo = item.m_extrainfo;
444 m_specialSort = item.m_specialSort;
445 m_bIsAlbum = item.m_bIsAlbum;
449 void CFileItem::Initialize()
451 m_musicInfoTag = NULL;
452 m_videoInfoTag = NULL;
454 m_pvrChannelInfoTag = NULL;
455 m_pvrRecordingInfoTag = NULL;
456 m_pvrTimerInfoTag = NULL;
457 m_pictureInfoTag = NULL;
458 m_bLabelPreformated=false;
461 m_bIsParentFolder=false;
462 m_bIsShareOrDrive = false;
463 m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
465 m_lStartPartNumber = 1;
469 m_iLockMode = LOCK_MODE_EVERYONE;
473 m_specialSort = SortSpecialNone;
476 void CFileItem::Reset()
478 // CGUIListItem members...
482 m_overlayIcon = ICON_OVERLAY_NONE;
486 m_strDVDLabel.clear();
490 m_strLockCode.clear();
492 delete m_musicInfoTag;
494 delete m_videoInfoTag;
498 delete m_pvrChannelInfoTag;
499 m_pvrChannelInfoTag=NULL;
500 delete m_pvrRecordingInfoTag;
501 m_pvrRecordingInfoTag=NULL;
502 delete m_pvrTimerInfoTag;
503 m_pvrTimerInfoTag=NULL;
504 delete m_pictureInfoTag;
505 m_pictureInfoTag=NULL;
513 void CFileItem::Archive(CArchive& ar)
515 CGUIListItem::Archive(ar);
519 ar << m_bIsParentFolder;
520 ar << m_bLabelPreformated;
522 ar << m_bIsShareOrDrive;
528 ar << m_iprogramCount;
530 ar << m_lStartOffset;
531 ar << m_lStartPartNumber;
535 ar << m_iBadPwdCount;
545 ar << *m_musicInfoTag;
552 ar << *m_videoInfoTag;
556 if (m_pictureInfoTag)
559 ar << *m_pictureInfoTag;
566 ar >> m_bIsParentFolder;
567 ar >> m_bLabelPreformated;
569 ar >> m_bIsShareOrDrive;
575 ar >> m_iprogramCount;
577 ar >> m_lStartOffset;
578 ar >> m_lStartPartNumber;
582 m_iLockMode = (LockType)temp;
584 ar >> m_iBadPwdCount;
590 m_specialSort = (SortSpecial)temp;
595 ar >> *GetMusicInfoTag();
598 ar >> *GetVideoInfoTag();
601 ar >> *GetPictureInfoTag();
607 void CFileItem::Serialize(CVariant& value) const
609 //CGUIListItem::Serialize(value["CGUIListItem"]);
611 value["strPath"] = m_strPath;
612 value["dateTime"] = (m_dateTime.IsValid()) ? m_dateTime.GetAsRFC1123DateTime() : "";
613 value["lastmodified"] = m_dateTime.IsValid() ? m_dateTime.GetAsDBDateTime() : "";
614 value["size"] = m_dwSize;
615 value["DVDLabel"] = m_strDVDLabel;
616 value["title"] = m_strTitle;
617 value["mimetype"] = m_mimetype;
618 value["extrainfo"] = m_extrainfo;
621 (*m_musicInfoTag).Serialize(value["musicInfoTag"]);
624 (*m_videoInfoTag).Serialize(value["videoInfoTag"]);
626 if (m_pictureInfoTag)
627 (*m_pictureInfoTag).Serialize(value["pictureInfoTag"]);
630 void CFileItem::ToSortable(SortItem &sortable, Field field) const
634 case FieldPath: sortable[FieldPath] = m_strPath; break;
635 case FieldDate: sortable[FieldDate] = (m_dateTime.IsValid()) ? m_dateTime.GetAsDBDateTime() : ""; break;
636 case FieldSize: sortable[FieldSize] = m_dwSize; break;
637 case FieldDriveType: sortable[FieldDriveType] = m_iDriveType; break;
638 case FieldStartOffset: sortable[FieldStartOffset] = m_lStartOffset; break;
639 case FieldEndOffset: sortable[FieldEndOffset] = m_lEndOffset; break;
640 case FieldProgramCount: sortable[FieldProgramCount] = m_iprogramCount; break;
641 case FieldBitrate: sortable[FieldBitrate] = m_dwSize; break;
642 case FieldTitle: sortable[FieldTitle] = m_strTitle; break;
643 // If there's ever a need to convert more properties from CGUIListItem it might be
644 // worth to make CGUIListItem implement ISortable as well and call it from here
648 if (HasMusicInfoTag())
649 GetMusicInfoTag()->ToSortable(sortable, field);
651 if (HasVideoInfoTag())
653 GetVideoInfoTag()->ToSortable(sortable, field);
655 if (GetVideoInfoTag()->m_type == MediaTypeTvShow)
657 if (field == FieldNumberOfEpisodes && HasProperty("totalepisodes"))
658 sortable[FieldNumberOfEpisodes] = GetProperty("totalepisodes");
659 if (field == FieldNumberOfWatchedEpisodes && HasProperty("unwatchedepisodes"))
660 sortable[FieldNumberOfWatchedEpisodes] = GetProperty("unwatchedepisodes");
664 if (HasPictureInfoTag())
665 GetPictureInfoTag()->ToSortable(sortable, field);
667 if (HasPVRChannelInfoTag())
668 GetPVRChannelInfoTag()->ToSortable(sortable, field);
671 void CFileItem::ToSortable(SortItem &sortable, const Fields &fields) const
673 Fields::const_iterator it;
674 for (it = fields.begin(); it != fields.end(); it++)
675 ToSortable(sortable, *it);
677 /* FieldLabel is used as a fallback by all sorters and therefore has to be present as well */
678 sortable[FieldLabel] = GetLabel();
679 /* FieldSortSpecial and FieldFolder are required in conjunction with all other sorters as well */
680 sortable[FieldSortSpecial] = m_specialSort;
681 sortable[FieldFolder] = m_bIsFolder;
684 bool CFileItem::Exists(bool bUseCache /* = true */) const
686 if (m_strPath.empty()
688 || IsInternetStream()
690 || IsVirtualDirectoryRoot()
694 if (IsVideoDb() && HasVideoInfoTag())
696 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
697 return dbItem.Exists();
700 std::string strPath = m_strPath;
702 if (URIUtils::IsMultiPath(strPath))
703 strPath = CMultiPathDirectory::GetFirstPath(strPath);
705 if (URIUtils::IsStack(strPath))
706 strPath = CStackDirectory::GetFirstStackedFile(strPath);
709 return CDirectory::Exists(strPath, bUseCache);
711 return CFile::Exists(strPath, bUseCache);
716 bool CFileItem::IsVideo() const
718 /* check preset mime type */
719 if( StringUtils::StartsWithNoCase(m_mimetype, "video/") )
722 if (HasVideoInfoTag()) return true;
723 if (HasMusicInfoTag()) return false;
724 if (HasPictureInfoTag()) return false;
725 if (IsPVRRecording()) return true;
727 if (IsHDHomeRun() || IsTuxBox() || URIUtils::IsDVD(m_strPath) || IsSlingbox())
730 std::string extension;
731 if( StringUtils::StartsWithNoCase(m_mimetype, "application/") )
732 { /* check for some standard types */
733 extension = m_mimetype.substr(12);
734 if( StringUtils::EqualsNoCase(extension, "ogg")
735 || StringUtils::EqualsNoCase(extension, "mp4")
736 || StringUtils::EqualsNoCase(extension, "mxf") )
740 return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_videoExtensions);
743 bool CFileItem::IsEPG() const
745 if (HasEPGInfoTag()) return true; /// is this enough?
749 bool CFileItem::IsPVRChannel() const
751 if (HasPVRChannelInfoTag()) return true; /// is this enough?
755 bool CFileItem::IsPVRRecording() const
757 if (HasPVRRecordingInfoTag()) return true; /// is this enough?
761 bool CFileItem::IsPVRTimer() const
763 if (HasPVRTimerInfoTag()) return true; /// is this enough?
767 bool CFileItem::IsDiscStub() const
769 if (IsVideoDb() && HasVideoInfoTag())
771 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
772 return dbItem.IsDiscStub();
775 return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_discStubExtensions);
778 bool CFileItem::IsAudio() const
780 /* check preset mime type */
781 if( StringUtils::StartsWithNoCase(m_mimetype, "audio/") )
784 if (HasMusicInfoTag()) return true;
785 if (HasVideoInfoTag()) return false;
786 if (HasPictureInfoTag()) return false;
787 if (IsCDDA()) return true;
789 if( StringUtils::StartsWithNoCase(m_mimetype, "application/") )
790 { /* check for some standard types */
791 std::string extension = m_mimetype.substr(12);
792 if( StringUtils::EqualsNoCase(extension, "ogg")
793 || StringUtils::EqualsNoCase(extension, "mp4")
794 || StringUtils::EqualsNoCase(extension, "mxf") )
798 return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_musicExtensions);
801 bool CFileItem::IsKaraoke() const
806 return CKaraokeLyricsFactory::HasLyrics( m_strPath );
809 bool CFileItem::IsPicture() const
811 if( StringUtils::StartsWithNoCase(m_mimetype, "image/") )
814 if (HasPictureInfoTag()) return true;
815 if (HasMusicInfoTag()) return false;
816 if (HasVideoInfoTag()) return false;
818 return CUtil::IsPicture(m_strPath);
821 bool CFileItem::IsLyrics() const
823 return URIUtils::HasExtension(m_strPath, ".cdg|.lrc");
826 bool CFileItem::IsCUESheet() const
828 return URIUtils::HasExtension(m_strPath, ".cue");
831 bool CFileItem::IsInternetStream(const bool bStrictCheck /* = false */) const
833 if (HasProperty("IsHTTPDirectory"))
836 return URIUtils::IsInternetStream(m_strPath, bStrictCheck);
839 bool CFileItem::IsFileFolder(EFileFolderType types) const
841 EFileFolderType always_type = EFILEFOLDER_TYPE_ALWAYS;
843 /* internet streams are not directly expanded */
844 if(IsInternetStream())
845 always_type = EFILEFOLDER_TYPE_ONCLICK;
848 if(types & always_type)
850 if( IsSmartPlayList()
851 || (IsPlayList() && g_advancedSettings.m_playlistAsFolders)
856 || IsType(".ogg|.oga|.nsf|.sid|.sap|.xsp")
857 #if defined(TARGET_ANDROID)
860 #ifdef HAS_ASAP_CODEC
861 || ASAPCodec::IsSupportedFormat(URIUtils::GetExtension(m_strPath))
867 if(types & EFILEFOLDER_TYPE_ONBROWSE)
869 if((IsPlayList() && !g_advancedSettings.m_playlistAsFolders)
878 bool CFileItem::IsSmartPlayList() const
880 if (HasProperty("library.smartplaylist") && GetProperty("library.smartplaylist").asBoolean())
883 return URIUtils::HasExtension(m_strPath, ".xsp");
886 bool CFileItem::IsLibraryFolder() const
888 if (HasProperty("library.filter") && GetProperty("library.filter").asBoolean())
891 return URIUtils::IsLibraryFolder(m_strPath);
894 bool CFileItem::IsPlayList() const
896 return CPlayListFactory::IsPlaylist(*this);
899 bool CFileItem::IsPythonScript() const
901 return URIUtils::HasExtension(m_strPath, ".py");
904 bool CFileItem::IsType(const char *ext) const
906 return URIUtils::HasExtension(m_strPath, ext);
909 bool CFileItem::IsNFO() const
911 return URIUtils::HasExtension(m_strPath, ".nfo");
914 bool CFileItem::IsDVDImage() const
916 return URIUtils::HasExtension(m_strPath, ".img|.iso|.nrg");
919 bool CFileItem::IsOpticalMediaFile() const
921 bool found = IsDVDFile(false, true);
927 bool CFileItem::IsDVDFile(bool bVobs /*= true*/, bool bIfos /*= true*/) const
929 std::string strFileName = URIUtils::GetFileName(m_strPath);
932 if (StringUtils::EqualsNoCase(strFileName, "video_ts.ifo")) return true;
933 if (StringUtils::StartsWithNoCase(strFileName, "vts_") && StringUtils::EndsWithNoCase(strFileName, "_0.ifo") && strFileName.length() == 12) return true;
937 if (StringUtils::EqualsNoCase(strFileName, "video_ts.vob")) return true;
938 if (StringUtils::StartsWithNoCase(strFileName, "vts_") && StringUtils::EndsWithNoCase(strFileName, ".vob")) return true;
944 bool CFileItem::IsBDFile() const
946 std::string strFileName = URIUtils::GetFileName(m_strPath);
947 return (StringUtils::EqualsNoCase(strFileName, "index.bdmv"));
950 bool CFileItem::IsRAR() const
952 return URIUtils::IsRAR(m_strPath);
955 bool CFileItem::IsAPK() const
957 return URIUtils::IsAPK(m_strPath);
960 bool CFileItem::IsZIP() const
962 return URIUtils::IsZIP(m_strPath);
965 bool CFileItem::IsCBZ() const
967 return URIUtils::HasExtension(m_strPath, ".cbz");
970 bool CFileItem::IsCBR() const
972 return URIUtils::HasExtension(m_strPath, ".cbr");
975 bool CFileItem::IsRSS() const
977 return StringUtils::StartsWithNoCase(m_strPath, "rss://") || URIUtils::HasExtension(m_strPath, ".rss")
978 || m_mimetype == "application/rss+xml";
981 bool CFileItem::IsAndroidApp() const
983 return URIUtils::IsAndroidApp(m_strPath);
986 bool CFileItem::IsStack() const
988 return URIUtils::IsStack(m_strPath);
991 bool CFileItem::IsPlugin() const
993 return URIUtils::IsPlugin(m_strPath);
996 bool CFileItem::IsScript() const
998 return URIUtils::IsScript(m_strPath);
1001 bool CFileItem::IsAddonsPath() const
1003 return URIUtils::IsAddonsPath(m_strPath);
1006 bool CFileItem::IsSourcesPath() const
1008 return URIUtils::IsSourcesPath(m_strPath);
1011 bool CFileItem::IsMultiPath() const
1013 return URIUtils::IsMultiPath(m_strPath);
1016 bool CFileItem::IsCDDA() const
1018 return URIUtils::IsCDDA(m_strPath);
1021 bool CFileItem::IsDVD() const
1023 return URIUtils::IsDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1026 bool CFileItem::IsOnDVD() const
1028 return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1031 bool CFileItem::IsNfs() const
1033 return URIUtils::IsNfs(m_strPath);
1036 bool CFileItem::IsAfp() const
1038 return URIUtils::IsAfp(m_strPath);
1041 bool CFileItem::IsOnLAN() const
1043 return URIUtils::IsOnLAN(m_strPath);
1046 bool CFileItem::IsISO9660() const
1048 return URIUtils::IsISO9660(m_strPath);
1051 bool CFileItem::IsRemote() const
1053 return URIUtils::IsRemote(m_strPath);
1056 bool CFileItem::IsSmb() const
1058 return URIUtils::IsSmb(m_strPath);
1061 bool CFileItem::IsURL() const
1063 return URIUtils::IsURL(m_strPath);
1066 bool CFileItem::IsDAAP() const
1068 return URIUtils::IsDAAP(m_strPath);
1071 bool CFileItem::IsTuxBox() const
1073 return URIUtils::IsTuxBox(m_strPath);
1076 bool CFileItem::IsMythTV() const
1078 return URIUtils::IsMythTV(m_strPath);
1081 bool CFileItem::IsHDHomeRun() const
1083 return URIUtils::IsHDHomeRun(m_strPath);
1086 bool CFileItem::IsSlingbox() const
1088 return URIUtils::IsSlingbox(m_strPath);
1091 bool CFileItem::IsVTP() const
1093 return URIUtils::IsVTP(m_strPath);
1096 bool CFileItem::IsPVR() const
1098 return CUtil::IsPVR(m_strPath);
1101 bool CFileItem::IsLiveTV() const
1103 return URIUtils::IsLiveTV(m_strPath);
1106 bool CFileItem::IsHD() const
1108 return URIUtils::IsHD(m_strPath);
1111 bool CFileItem::IsMusicDb() const
1113 return URIUtils::IsMusicDb(m_strPath);
1116 bool CFileItem::IsVideoDb() const
1118 return URIUtils::IsVideoDb(m_strPath);
1121 bool CFileItem::IsVirtualDirectoryRoot() const
1123 return (m_bIsFolder && m_strPath.empty());
1126 bool CFileItem::IsRemovable() const
1128 return IsOnDVD() || IsCDDA() || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE;
1131 bool CFileItem::IsReadOnly() const
1133 if (IsParentFolder()) return true;
1134 if (m_bIsShareOrDrive) return true;
1135 return !CUtil::SupportsWriteFileOperations(m_strPath);
1138 void CFileItem::FillInDefaultIcon()
1140 //CLog::Log(LOGINFO, "FillInDefaultIcon(%s)", pItem->GetLabel().c_str());
1141 // find the default icon for a file or folder item
1142 // for files this can be the (depending on the file type)
1143 // default picture for photo's
1144 // default picture for songs
1145 // default picture for videos
1146 // default picture for shortcuts
1147 // default picture for playlists
1148 // or the icon embedded in an .xbe
1151 // for .. folders the default picture for parent folder
1152 // for other folders the defaultFolder.png
1154 if (GetIconImage().empty())
1158 /* To reduce the average runtime of this code, this list should
1159 * be ordered with most frequently seen types first. Also bear
1160 * in mind the complexity of the code behind the check in the
1161 * case of IsWhatater() returns false.
1165 if (GetPVRChannelInfoTag()->IsRadio())
1166 SetIconImage("DefaultAudio.png");
1168 SetIconImage("DefaultVideo.png");
1170 else if ( IsLiveTV() )
1173 SetIconImage("DefaultVideo.png");
1175 else if ( URIUtils::IsArchive(m_strPath) )
1177 SetIconImage("DefaultFile.png");
1179 else if ( IsAudio() )
1182 SetIconImage("DefaultAudio.png");
1184 else if ( IsVideo() )
1187 SetIconImage("DefaultVideo.png");
1189 else if (IsPVRRecording())
1191 SetIconImage("DefaultVideo.png");
1193 else if (IsPVRTimer())
1195 SetIconImage("DefaultVideo.png");
1197 else if ( IsPicture() )
1200 SetIconImage("DefaultPicture.png");
1202 else if ( IsPlayList() )
1204 SetIconImage("DefaultPlaylist.png");
1206 else if ( IsPythonScript() )
1208 SetIconImage("DefaultScript.png");
1212 // default icon for unknown file type
1213 SetIconImage("DefaultFile.png");
1220 SetIconImage("DefaultPlaylist.png");
1222 else if (IsParentFolder())
1224 SetIconImage("DefaultFolderBack.png");
1228 SetIconImage("DefaultFolder.png");
1232 // Set the icon overlays (if applicable)
1235 if (URIUtils::IsInRAR(m_strPath))
1236 SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR);
1237 else if (URIUtils::IsInZIP(m_strPath))
1238 SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP);
1242 void CFileItem::RemoveExtension()
1246 std::string strLabel = GetLabel();
1247 URIUtils::RemoveExtension(strLabel);
1251 void CFileItem::CleanString()
1256 std::string strLabel = GetLabel();
1257 std::string strTitle, strTitleAndYear, strYear;
1258 CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, true );
1259 SetLabel(strTitleAndYear);
1262 void CFileItem::SetLabel(const std::string &strLabel)
1266 m_bIsParentFolder=true;
1268 m_specialSort = SortSpecialOnTop;
1269 SetLabelPreformated(true);
1271 CGUIListItem::SetLabel(strLabel);
1274 void CFileItem::SetFileSizeLabel()
1276 if( m_bIsFolder && m_dwSize == 0 )
1279 SetLabel2(StringUtils::SizeToString(m_dwSize));
1282 bool CFileItem::CanQueue() const
1287 void CFileItem::SetCanQueue(bool bYesNo)
1292 bool CFileItem::IsParentFolder() const
1294 return m_bIsParentFolder;
1297 void CFileItem::FillInMimeType(bool lookup /*= true*/)
1299 // TODO: adapt this to use CMime::GetMimeType()
1300 if (m_mimetype.empty())
1303 m_mimetype = "x-directory/normal";
1304 else if( m_pvrChannelInfoTag )
1305 m_mimetype = m_pvrChannelInfoTag->InputFormat();
1306 else if( StringUtils::StartsWithNoCase(m_strPath, "shout://")
1307 || StringUtils::StartsWithNoCase(m_strPath, "http://")
1308 || StringUtils::StartsWithNoCase(m_strPath, "https://"))
1310 // If lookup is false, bail out early to leave mime type empty
1314 CCurlFile::GetMimeType(GetURL(), m_mimetype);
1316 // try to get mime-type again but with an NSPlayer User-Agent
1317 // in order for server to provide correct mime-type. Allows us
1318 // to properly detect an MMS stream
1319 if (StringUtils::StartsWithNoCase(m_mimetype, "video/x-ms-"))
1320 CCurlFile::GetMimeType(GetURL(), m_mimetype, "NSPlayer/11.00.6001.7000");
1322 // make sure there are no options set in mime-type
1323 // mime-type can look like "video/x-ms-asf ; charset=utf8"
1324 size_t i = m_mimetype.find(';');
1325 if(i != std::string::npos)
1326 m_mimetype.erase(i, m_mimetype.length() - i);
1327 StringUtils::Trim(m_mimetype);
1330 m_mimetype = CMime::GetMimeType(*this);
1332 // if it's still empty set to an unknown type
1333 if (m_mimetype.empty())
1334 m_mimetype = "application/octet-stream";
1337 // change protocol to mms for the following mime-type. Allows us to create proper FileMMS.
1338 if( StringUtils::StartsWithNoCase(m_mimetype, "application/vnd.ms.wms-hdr.asfv1") || StringUtils::StartsWithNoCase(m_mimetype, "application/x-mms-framed") )
1339 StringUtils::Replace(m_strPath, "http:", "mms:");
1342 bool CFileItem::IsSamePath(const CFileItem *item) const
1347 if (item->GetPath() == m_strPath)
1349 if (item->HasProperty("item_start") || HasProperty("item_start"))
1350 return (item->GetProperty("item_start") == GetProperty("item_start"));
1353 if (HasVideoInfoTag() && item->HasVideoInfoTag())
1355 if (m_videoInfoTag->m_iDbId != -1 && item->m_videoInfoTag->m_iDbId != -1)
1356 return ((m_videoInfoTag->m_iDbId == item->m_videoInfoTag->m_iDbId) &&
1357 (m_videoInfoTag->m_type == item->m_videoInfoTag->m_type));
1359 if (IsMusicDb() && HasMusicInfoTag())
1361 CFileItem dbItem(m_musicInfoTag->GetURL(), false);
1362 if (HasProperty("item_start"))
1363 dbItem.SetProperty("item_start", GetProperty("item_start"));
1364 return dbItem.IsSamePath(item);
1366 if (IsVideoDb() && HasVideoInfoTag())
1368 CFileItem dbItem(m_videoInfoTag->m_strFileNameAndPath, false);
1369 if (HasProperty("item_start"))
1370 dbItem.SetProperty("item_start", GetProperty("item_start"));
1371 return dbItem.IsSamePath(item);
1373 if (item->IsMusicDb() && item->HasMusicInfoTag())
1375 CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
1376 if (item->HasProperty("item_start"))
1377 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1378 return IsSamePath(&dbItem);
1380 if (item->IsVideoDb() && item->HasVideoInfoTag())
1382 CFileItem dbItem(item->m_videoInfoTag->m_strFileNameAndPath, false);
1383 if (item->HasProperty("item_start"))
1384 dbItem.SetProperty("item_start", item->GetProperty("item_start"));
1385 return IsSamePath(&dbItem);
1387 if (HasProperty("original_listitem_url"))
1388 return (GetProperty("original_listitem_url") == item->GetPath());
1392 bool CFileItem::IsAlbum() const
1397 void CFileItem::UpdateInfo(const CFileItem &item, bool replaceLabels /*=true*/)
1399 if (item.HasVideoInfoTag())
1400 { // copy info across (TODO: premiered info is normally stored in m_dateTime by the db)
1401 *GetVideoInfoTag() = *item.GetVideoInfoTag();
1402 // preferably use some information from PVR info tag if available
1403 if (HasPVRRecordingInfoTag())
1404 GetPVRRecordingInfoTag()->CopyClientInfo(GetVideoInfoTag());
1405 SetOverlayImage(ICON_OVERLAY_UNWATCHED, GetVideoInfoTag()->m_playCount > 0);
1408 if (item.HasMusicInfoTag())
1410 *GetMusicInfoTag() = *item.GetMusicInfoTag();
1413 if (item.HasPictureInfoTag())
1415 *GetPictureInfoTag() = *item.GetPictureInfoTag();
1418 if (replaceLabels && !item.GetLabel().empty())
1419 SetLabel(item.GetLabel());
1420 if (replaceLabels && !item.GetLabel2().empty())
1421 SetLabel2(item.GetLabel2());
1422 if (!item.GetArt("thumb").empty())
1423 SetArt("thumb", item.GetArt("thumb"));
1424 if (!item.GetIconImage().empty())
1425 SetIconImage(item.GetIconImage());
1426 AppendProperties(item);
1429 void CFileItem::SetFromVideoInfoTag(const CVideoInfoTag &video)
1431 if (!video.m_strTitle.empty())
1432 SetLabel(video.m_strTitle);
1433 if (video.m_strFileNameAndPath.empty())
1435 m_strPath = video.m_strPath;
1436 URIUtils::AddSlashAtEnd(m_strPath);
1441 m_strPath = video.m_strFileNameAndPath;
1442 m_bIsFolder = false;
1445 *GetVideoInfoTag() = video;
1446 if (video.m_iSeason == 0)
1447 SetProperty("isspecial", "true");
1448 FillInDefaultIcon();
1449 FillInMimeType(false);
1452 void CFileItem::SetFromAlbum(const CAlbum &album)
1454 if (!album.strAlbum.empty())
1455 SetLabel(album.strAlbum);
1457 m_strLabel2 = StringUtils::Join(album.artist, g_advancedSettings.m_musicItemSeparator);
1458 GetMusicInfoTag()->SetAlbum(album);
1460 CMusicDatabase::SetPropertiesFromAlbum(*this,album);
1461 FillInMimeType(false);
1464 void CFileItem::SetFromSong(const CSong &song)
1466 if (!song.strTitle.empty())
1467 SetLabel(song.strTitle);
1468 if (!song.strFileName.empty())
1469 m_strPath = song.strFileName;
1470 GetMusicInfoTag()->SetSong(song);
1471 m_lStartOffset = song.iStartOffset;
1472 m_lStartPartNumber = 1;
1473 SetProperty("item_start", song.iStartOffset);
1474 m_lEndOffset = song.iEndOffset;
1475 if (!song.strThumb.empty())
1476 SetArt("thumb", song.strThumb);
1477 FillInMimeType(false);
1480 std::string CFileItem::GetOpticalMediaPath() const
1483 std::string dvdPath;
1484 path = URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS.IFO");
1485 if (CFile::Exists(path))
1489 dvdPath = URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS");
1490 path = URIUtils::AddFileToFolder(dvdPath, "VIDEO_TS.IFO");
1492 if (CFile::Exists(path))
1495 #ifdef HAVE_LIBBLURAY
1496 if (dvdPath.empty())
1498 path = URIUtils::AddFileToFolder(GetPath(), "index.bdmv");
1499 if (CFile::Exists(path))
1503 dvdPath = URIUtils::AddFileToFolder(GetPath(), "BDMV");
1504 path = URIUtils::AddFileToFolder(dvdPath, "index.bdmv");
1506 if (CFile::Exists(path))
1515 TODO: Ideally this (and SetPath) would not be available outside of construction
1516 for CFileItem objects, or at least restricted to essentially be equivalent
1517 to construction. This would require re-formulating a bunch of CFileItem
1518 construction, and also allowing CFileItemList to have it's own (public)
1519 SetURL() function, so for now we give direct access.
1521 void CFileItem::SetURL(const CURL& url)
1523 m_strPath = url.Get();
1526 const CURL CFileItem::GetURL() const
1528 CURL url(m_strPath);
1532 bool CFileItem::IsURL(const CURL& url) const
1534 return IsPath(url.Get());
1537 bool CFileItem::IsPath(const std::string& path) const
1539 return URIUtils::PathEquals(m_strPath, path);
1542 /////////////////////////////////////////////////////////////////////////////////
1546 //////////////////////////////////////////////////////////////////////////////////
1548 CFileItemList::CFileItemList()
1550 m_fastLookup = false;
1552 m_cacheToDisc = CACHE_IF_SLOW;
1553 m_sortIgnoreFolders = false;
1554 m_replaceListing = false;
1557 CFileItemList::CFileItemList(const std::string& strPath) : CFileItem(strPath, true)
1559 m_fastLookup = false;
1560 m_cacheToDisc = CACHE_IF_SLOW;
1561 m_sortIgnoreFolders = false;
1562 m_replaceListing = false;
1565 CFileItemList::~CFileItemList()
1570 CFileItemPtr CFileItemList::operator[] (int iItem)
1575 const CFileItemPtr CFileItemList::operator[] (int iItem) const
1580 CFileItemPtr CFileItemList::operator[] (const std::string& strPath)
1582 return Get(strPath);
1585 const CFileItemPtr CFileItemList::operator[] (const std::string& strPath) const
1587 return Get(strPath);
1590 void CFileItemList::SetFastLookup(bool fastLookup)
1592 CSingleLock lock(m_lock);
1594 if (fastLookup && !m_fastLookup)
1595 { // generate the map
1597 for (unsigned int i=0; i < m_items.size(); i++)
1599 CFileItemPtr pItem = m_items[i];
1600 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1603 if (!fastLookup && m_fastLookup)
1605 m_fastLookup = fastLookup;
1608 bool CFileItemList::Contains(const std::string& fileName) const
1610 CSingleLock lock(m_lock);
1613 return m_map.find(fileName) != m_map.end();
1616 for (unsigned int i = 0; i < m_items.size(); i++)
1618 const CFileItemPtr pItem = m_items[i];
1619 if (pItem->IsPath(fileName))
1625 void CFileItemList::Clear()
1627 CSingleLock lock(m_lock);
1630 m_sortDescription.sortBy = SortByNone;
1631 m_sortDescription.sortOrder = SortOrderNone;
1632 m_sortDescription.sortAttributes = SortAttributeNone;
1633 m_sortIgnoreFolders = false;
1634 m_cacheToDisc = CACHE_IF_SLOW;
1635 m_sortDetails.clear();
1636 m_replaceListing = false;
1640 void CFileItemList::ClearItems()
1642 CSingleLock lock(m_lock);
1643 // make sure we free the memory of the items (these are GUIControls which may have allocated resources)
1645 for (unsigned int i = 0; i < m_items.size(); i++)
1647 CFileItemPtr item = m_items[i];
1654 void CFileItemList::Add(const CFileItemPtr &pItem)
1656 CSingleLock lock(m_lock);
1658 m_items.push_back(pItem);
1661 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1665 void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition)
1667 CSingleLock lock(m_lock);
1669 if (itemPosition >= 0)
1671 m_items.insert(m_items.begin()+itemPosition, pItem);
1675 m_items.insert(m_items.begin()+(m_items.size()+itemPosition), pItem);
1679 m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1683 void CFileItemList::Remove(CFileItem* pItem)
1685 CSingleLock lock(m_lock);
1687 for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it)
1689 if (pItem == it->get())
1694 m_map.erase(pItem->GetPath());
1701 void CFileItemList::Remove(int iItem)
1703 CSingleLock lock(m_lock);
1705 if (iItem >= 0 && iItem < (int)Size())
1707 CFileItemPtr pItem = *(m_items.begin() + iItem);
1710 m_map.erase(pItem->GetPath());
1712 m_items.erase(m_items.begin() + iItem);
1716 void CFileItemList::Append(const CFileItemList& itemlist)
1718 CSingleLock lock(m_lock);
1720 for (int i = 0; i < itemlist.Size(); ++i)
1724 void CFileItemList::Assign(const CFileItemList& itemlist, bool append)
1726 CSingleLock lock(m_lock);
1730 SetPath(itemlist.GetPath());
1731 SetLabel(itemlist.GetLabel());
1732 m_sortDetails = itemlist.m_sortDetails;
1733 m_sortDescription = itemlist.m_sortDescription;
1734 m_replaceListing = itemlist.m_replaceListing;
1735 m_content = itemlist.m_content;
1736 m_mapProperties = itemlist.m_mapProperties;
1737 m_cacheToDisc = itemlist.m_cacheToDisc;
1740 bool CFileItemList::Copy(const CFileItemList& items, bool copyItems /* = true */)
1742 // assign all CFileItem parts
1743 *(CFileItem*)this = *(CFileItem*)&items;
1745 // assign the rest of the CFileItemList properties
1746 m_replaceListing = items.m_replaceListing;
1747 m_content = items.m_content;
1748 m_mapProperties = items.m_mapProperties;
1749 m_cacheToDisc = items.m_cacheToDisc;
1750 m_sortDetails = items.m_sortDetails;
1751 m_sortDescription = items.m_sortDescription;
1752 m_sortIgnoreFolders = items.m_sortIgnoreFolders;
1756 // make a copy of each item
1757 for (int i = 0; i < items.Size(); i++)
1759 CFileItemPtr newItem(new CFileItem(*items[i]));
1767 CFileItemPtr CFileItemList::Get(int iItem)
1769 CSingleLock lock(m_lock);
1771 if (iItem > -1 && iItem < (int)m_items.size())
1772 return m_items[iItem];
1774 return CFileItemPtr();
1777 const CFileItemPtr CFileItemList::Get(int iItem) const
1779 CSingleLock lock(m_lock);
1781 if (iItem > -1 && iItem < (int)m_items.size())
1782 return m_items[iItem];
1784 return CFileItemPtr();
1787 CFileItemPtr CFileItemList::Get(const std::string& strPath)
1789 CSingleLock lock(m_lock);
1793 IMAPFILEITEMS it=m_map.find(strPath);
1794 if (it != m_map.end())
1797 return CFileItemPtr();
1800 for (unsigned int i = 0; i < m_items.size(); i++)
1802 CFileItemPtr pItem = m_items[i];
1803 if (pItem->IsPath(strPath))
1807 return CFileItemPtr();
1810 const CFileItemPtr CFileItemList::Get(const std::string& strPath) const
1812 CSingleLock lock(m_lock);
1816 map<std::string, CFileItemPtr>::const_iterator it=m_map.find(strPath);
1817 if (it != m_map.end())
1820 return CFileItemPtr();
1823 for (unsigned int i = 0; i < m_items.size(); i++)
1825 CFileItemPtr pItem = m_items[i];
1826 if (pItem->IsPath(strPath))
1830 return CFileItemPtr();
1833 int CFileItemList::Size() const
1835 CSingleLock lock(m_lock);
1836 return (int)m_items.size();
1839 bool CFileItemList::IsEmpty() const
1841 CSingleLock lock(m_lock);
1842 return (m_items.size() <= 0);
1845 void CFileItemList::Reserve(int iCount)
1847 CSingleLock lock(m_lock);
1848 m_items.reserve(iCount);
1851 void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func)
1853 CSingleLock lock(m_lock);
1854 std::stable_sort(m_items.begin(), m_items.end(), func);
1857 void CFileItemList::FillSortFields(FILEITEMFILLFUNC func)
1859 CSingleLock lock(m_lock);
1860 std::for_each(m_items.begin(), m_items.end(), func);
1863 void CFileItemList::Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute sortAttributes /* = SortAttributeNone */)
1865 if (sortBy == SortByNone ||
1866 (m_sortDescription.sortBy == sortBy && m_sortDescription.sortOrder == sortOrder &&
1867 m_sortDescription.sortAttributes == sortAttributes))
1870 SortDescription sorting;
1871 sorting.sortBy = sortBy;
1872 sorting.sortOrder = sortOrder;
1873 sorting.sortAttributes = sortAttributes;
1876 m_sortDescription = sorting;
1879 void CFileItemList::Sort(SortDescription sortDescription)
1881 if (sortDescription.sortBy == SortByFile ||
1882 sortDescription.sortBy == SortBySortTitle ||
1883 sortDescription.sortBy == SortByDateAdded ||
1884 sortDescription.sortBy == SortByRating ||
1885 sortDescription.sortBy == SortByYear ||
1886 sortDescription.sortBy == SortByPlaylistOrder ||
1887 sortDescription.sortBy == SortByLastPlayed ||
1888 sortDescription.sortBy == SortByPlaycount)
1889 sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders);
1891 if (sortDescription.sortBy == SortByNone ||
1892 (m_sortDescription.sortBy == sortDescription.sortBy && m_sortDescription.sortOrder == sortDescription.sortOrder &&
1893 m_sortDescription.sortAttributes == sortDescription.sortAttributes))
1896 if (m_sortIgnoreFolders)
1897 sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders);
1899 const Fields fields = SortUtils::GetFieldsForSorting(sortDescription.sortBy);
1900 SortItems sortItems((size_t)Size());
1901 for (int index = 0; index < Size(); index++)
1903 sortItems[index] = boost::shared_ptr<SortItem>(new SortItem);
1904 m_items[index]->ToSortable(*sortItems[index], fields);
1905 (*sortItems[index])[FieldId] = index;
1909 SortUtils::Sort(sortDescription, sortItems);
1911 // apply the new order to the existing CFileItems
1912 VECFILEITEMS sortedFileItems;
1913 sortedFileItems.reserve(Size());
1914 for (SortItems::const_iterator it = sortItems.begin(); it != sortItems.end(); it++)
1916 CFileItemPtr item = m_items[(int)(*it)->at(FieldId).asInteger()];
1917 // Set the sort label in the CFileItem
1918 item->SetSortLabel((*it)->at(FieldSort).asWideString());
1920 sortedFileItems.push_back(item);
1923 // replace the current list with the re-ordered one
1924 m_items.assign(sortedFileItems.begin(), sortedFileItems.end());
1927 void CFileItemList::Randomize()
1929 CSingleLock lock(m_lock);
1930 random_shuffle(m_items.begin(), m_items.end());
1933 void CFileItemList::Archive(CArchive& ar)
1935 CSingleLock lock(m_lock);
1938 CFileItem::Archive(ar);
1941 if (m_items.size() > 0 && m_items[0]->IsParentFolder())
1944 ar << (int)(m_items.size() - i);
1948 ar << (int)m_sortDescription.sortBy;
1949 ar << (int)m_sortDescription.sortOrder;
1950 ar << (int)m_sortDescription.sortAttributes;
1951 ar << m_sortIgnoreFolders;
1952 ar << (int)m_cacheToDisc;
1954 ar << (int)m_sortDetails.size();
1955 for (unsigned int j = 0; j < m_sortDetails.size(); ++j)
1957 const SORT_METHOD_DETAILS &details = m_sortDetails[j];
1958 ar << (int)details.m_sortDescription.sortBy;
1959 ar << (int)details.m_sortDescription.sortOrder;
1960 ar << (int)details.m_sortDescription.sortAttributes;
1961 ar << details.m_buttonLabel;
1962 ar << details.m_labelMasks.m_strLabelFile;
1963 ar << details.m_labelMasks.m_strLabelFolder;
1964 ar << details.m_labelMasks.m_strLabel2File;
1965 ar << details.m_labelMasks.m_strLabel2Folder;
1970 for (; i < (int)m_items.size(); ++i)
1972 CFileItemPtr pItem = m_items[i];
1978 CFileItemPtr pParent;
1981 CFileItemPtr pItem=m_items[0];
1982 if (pItem->IsParentFolder())
1983 pParent.reset(new CFileItem(*pItem));
1986 SetFastLookup(false);
1990 CFileItem::Archive(ar);
1999 m_items.reserve(iSize + 1);
2000 m_items.push_back(pParent);
2003 m_items.reserve(iSize);
2005 bool fastLookup=false;
2009 ar >> (int&)tempint;
2010 m_sortDescription.sortBy = (SortBy)tempint;
2011 ar >> (int&)tempint;
2012 m_sortDescription.sortOrder = (SortOrder)tempint;
2013 ar >> (int&)tempint;
2014 m_sortDescription.sortAttributes = (SortAttribute)tempint;
2015 ar >> m_sortIgnoreFolders;
2016 ar >> (int&)tempint;
2017 m_cacheToDisc = CACHE_TYPE(tempint);
2019 unsigned int detailSize = 0;
2021 for (unsigned int j = 0; j < detailSize; ++j)
2023 SORT_METHOD_DETAILS details;
2024 ar >> (int&)tempint;
2025 details.m_sortDescription.sortBy = (SortBy)tempint;
2026 ar >> (int&)tempint;
2027 details.m_sortDescription.sortOrder = (SortOrder)tempint;
2028 ar >> (int&)tempint;
2029 details.m_sortDescription.sortAttributes = (SortAttribute)tempint;
2030 ar >> details.m_buttonLabel;
2031 ar >> details.m_labelMasks.m_strLabelFile;
2032 ar >> details.m_labelMasks.m_strLabelFolder;
2033 ar >> details.m_labelMasks.m_strLabel2File;
2034 ar >> details.m_labelMasks.m_strLabel2Folder;
2035 m_sortDetails.push_back(details);
2040 for (int i = 0; i < iSize; ++i)
2042 CFileItemPtr pItem(new CFileItem);
2047 SetFastLookup(fastLookup);
2051 void CFileItemList::FillInDefaultIcons()
2053 CSingleLock lock(m_lock);
2054 for (int i = 0; i < (int)m_items.size(); ++i)
2056 CFileItemPtr pItem = m_items[i];
2057 pItem->FillInDefaultIcon();
2061 int CFileItemList::GetFolderCount() const
2063 CSingleLock lock(m_lock);
2064 int nFolderCount = 0;
2065 for (int i = 0; i < (int)m_items.size(); i++)
2067 CFileItemPtr pItem = m_items[i];
2068 if (pItem->m_bIsFolder)
2072 return nFolderCount;
2075 int CFileItemList::GetObjectCount() const
2077 CSingleLock lock(m_lock);
2079 int numObjects = (int)m_items.size();
2080 if (numObjects && m_items[0]->IsParentFolder())
2086 int CFileItemList::GetFileCount() const
2088 CSingleLock lock(m_lock);
2090 for (int i = 0; i < (int)m_items.size(); i++)
2092 CFileItemPtr pItem = m_items[i];
2093 if (!pItem->m_bIsFolder)
2100 int CFileItemList::GetSelectedCount() const
2102 CSingleLock lock(m_lock);
2104 for (int i = 0; i < (int)m_items.size(); i++)
2106 CFileItemPtr pItem = m_items[i];
2107 if (pItem->IsSelected())
2114 void CFileItemList::FilterCueItems()
2116 CSingleLock lock(m_lock);
2117 // Handle .CUE sheet files...
2118 VECSONGS itemstoadd;
2119 vector<string> itemstodelete;
2120 for (int i = 0; i < (int)m_items.size(); i++)
2122 CFileItemPtr pItem = m_items[i];
2123 if (!pItem->m_bIsFolder)
2124 { // see if it's a .CUE sheet
2125 if (pItem->IsCUESheet())
2127 CCueDocument cuesheet;
2128 if (cuesheet.Parse(pItem->GetPath()))
2131 cuesheet.GetSongs(newitems);
2133 std::vector<CStdString> MediaFileVec;
2134 cuesheet.GetMediaFiles(MediaFileVec);
2136 // queue the cue sheet and the underlying media file for deletion
2137 for(std::vector<CStdString>::iterator itMedia = MediaFileVec.begin(); itMedia != MediaFileVec.end(); itMedia++)
2139 std::string strMediaFile = *itMedia;
2140 std::string fileFromCue = strMediaFile; // save the file from the cue we're matching against,
2141 // as we're going to search for others here...
2142 bool bFoundMediaFile = CFile::Exists(strMediaFile);
2143 // queue the cue sheet and the underlying media file for deletion
2144 if (!bFoundMediaFile)
2146 // try file in same dir, not matching case...
2147 if (Contains(strMediaFile))
2149 bFoundMediaFile = true;
2153 // try removing the .cue extension...
2154 strMediaFile = pItem->GetPath();
2155 URIUtils::RemoveExtension(strMediaFile);
2156 CFileItem item(strMediaFile, false);
2157 if (item.IsAudio() && Contains(strMediaFile))
2159 bFoundMediaFile = true;
2162 { // try replacing the extension with one of our allowed ones.
2163 vector<string> extensions = StringUtils::Split(g_advancedSettings.m_musicExtensions, "|");
2164 for (vector<string>::const_iterator i = extensions.begin(); i != extensions.end(); ++i)
2166 strMediaFile = URIUtils::ReplaceExtension(pItem->GetPath(), *i);
2167 CFileItem item(strMediaFile, false);
2168 if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile))
2170 bFoundMediaFile = true;
2177 if (bFoundMediaFile)
2179 itemstodelete.push_back(pItem->GetPath());
2180 itemstodelete.push_back(strMediaFile);
2181 // get the additional stuff (year, genre etc.) from the underlying media files tag.
2183 auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(strMediaFile));
2184 if (NULL != pLoader.get())
2187 pLoader->Load(strMediaFile, tag);
2189 // fill in any missing entries from underlying media file
2190 for (int j = 0; j < (int)newitems.size(); j++)
2192 CSong song = newitems[j];
2193 // only for songs that actually match the current media file
2194 if (song.strFileName == fileFromCue)
2196 // we might have a new media file from the above matching code
2197 song.strFileName = strMediaFile;
2200 if (song.strAlbum.empty() && !tag.GetAlbum().empty()) song.strAlbum = tag.GetAlbum();
2201 if (song.albumArtist.empty() && !tag.GetAlbumArtist().empty()) song.albumArtist = tag.GetAlbumArtist();
2202 if (song.genre.empty() && !tag.GetGenre().empty()) song.genre = tag.GetGenre();
2203 if (song.artist.empty() && !tag.GetArtist().empty()) song.artist = tag.GetArtist();
2204 if (tag.GetDiscNumber()) song.iTrack |= (tag.GetDiscNumber() << 16); // see CMusicInfoTag::GetDiscNumber()
2205 SYSTEMTIME dateTime;
2206 tag.GetReleaseDate(dateTime);
2207 if (dateTime.wYear) song.iYear = dateTime.wYear;
2208 if (song.embeddedArt.empty() && !tag.GetCoverArtInfo().empty())
2209 song.embeddedArt = tag.GetCoverArtInfo();
2211 if (!song.iDuration && tag.GetDuration() > 0)
2212 { // must be the last song
2213 song.iDuration = (tag.GetDuration() * 75 - song.iStartOffset + 37) / 75;
2215 // add this item to the list
2216 itemstoadd.push_back(song);
2221 { // remove the .cue sheet from the directory
2222 itemstodelete.push_back(pItem->GetPath());
2227 { // remove the .cue sheet from the directory (can't parse it - no point listing it)
2228 itemstodelete.push_back(pItem->GetPath());
2233 // now delete the .CUE files and underlying media files.
2234 for (int i = 0; i < (int)itemstodelete.size(); i++)
2236 for (int j = 0; j < (int)m_items.size(); j++)
2238 CFileItemPtr pItem = m_items[j];
2239 if (stricmp(pItem->GetPath().c_str(), itemstodelete[i].c_str()) == 0)
2240 { // delete this item
2241 m_items.erase(m_items.begin() + j);
2246 // and add the files from the .CUE sheet
2247 for (int i = 0; i < (int)itemstoadd.size(); i++)
2249 // now create the file item, and add to the item list.
2250 CFileItemPtr pItem(new CFileItem(itemstoadd[i]));
2251 m_items.push_back(pItem);
2255 // Remove the extensions from the filenames
2256 void CFileItemList::RemoveExtensions()
2258 CSingleLock lock(m_lock);
2259 for (int i = 0; i < Size(); ++i)
2260 m_items[i]->RemoveExtension();
2263 void CFileItemList::Stack(bool stackFiles /* = true */)
2265 CSingleLock lock(m_lock);
2268 if (IsVirtualDirectoryRoot() || IsLiveTV() || IsSourcesPath())
2271 SetProperty("isstacked", true);
2273 // items needs to be sorted for stuff below to work properly
2274 Sort(SortByLabel, SortOrderAscending);
2282 void CFileItemList::StackFolders()
2284 // Precompile our REs
2285 VECCREGEXP folderRegExps;
2286 CRegExp folderRegExp(true, CRegExp::autoUtf8);
2287 const vector<string>& strFolderRegExps = g_advancedSettings.m_folderStackRegExps;
2289 vector<string>::const_iterator strExpression = strFolderRegExps.begin();
2290 while (strExpression != strFolderRegExps.end())
2292 if (!folderRegExp.RegComp(*strExpression))
2293 CLog::Log(LOGERROR, "%s: Invalid folder stack RegExp:'%s'", __FUNCTION__, strExpression->c_str());
2295 folderRegExps.push_back(folderRegExp);
2301 for (int i = 0; i < Size(); i++)
2303 CFileItemPtr item = Get(i);
2304 // combined the folder checks
2305 if (item->m_bIsFolder)
2307 // only check known fast sources?
2309 // 1. rars and zips may be on slow sources? is this supposed to be allowed?
2310 if( !item->IsRemote()
2314 || URIUtils::IsInRAR(item->GetPath())
2315 || URIUtils::IsInZIP(item->GetPath())
2316 || URIUtils::IsOnLAN(item->GetPath())
2319 // stack cd# folders if contains only a single video file
2323 VECCREGEXP::iterator expr = folderRegExps.begin();
2324 while (!bMatch && expr != folderRegExps.end())
2326 //CLog::Log(LOGDEBUG,"%s: Running expression %s on %s", __FUNCTION__, expr->GetPattern().c_str(), item->GetLabel().c_str());
2327 bMatch = (expr->RegFind(item->GetLabel().c_str()) != -1);
2330 CFileItemList items;
2331 CDirectory::GetDirectory(item->GetPath(),items,g_advancedSettings.m_videoExtensions);
2332 // optimized to only traverse listing once by checking for filecount
2333 // and recording last file item for later use
2336 for (int j = 0; j < items.Size(); j++)
2338 if (!items[j]->m_bIsFolder)
2349 *item = *items[index];
2354 // check for dvd folders
2357 std::string dvdPath = item->GetOpticalMediaPath();
2359 if (!dvdPath.empty())
2361 // NOTE: should this be done for the CD# folders too?
2362 item->m_bIsFolder = false;
2363 item->SetPath(dvdPath);
2364 item->SetLabel2("");
2365 item->SetLabelPreformated(true);
2366 m_sortDescription.sortBy = SortByNone; /* sorting is now broken */
2374 void CFileItemList::StackFiles()
2376 // Precompile our REs
2377 VECCREGEXP stackRegExps;
2378 CRegExp tmpRegExp(true, CRegExp::autoUtf8);
2379 const vector<string>& strStackRegExps = g_advancedSettings.m_videoStackRegExps;
2380 vector<string>::const_iterator strRegExp = strStackRegExps.begin();
2381 while (strRegExp != strStackRegExps.end())
2383 if (tmpRegExp.RegComp(*strRegExp))
2385 if (tmpRegExp.GetCaptureTotal() == 4)
2386 stackRegExps.push_back(tmpRegExp);
2388 CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have 4 captures.", strRegExp->c_str());
2393 // now stack the files, some of which may be from the previous stack iteration
2397 CFileItemPtr item1 = Get(i);
2399 // skip folders, nfo files, playlists
2400 if (item1->m_bIsFolder
2401 || item1->IsParentFolder()
2403 || item1->IsPlayList()
2413 std::string stackName;
2415 std::string filePath;
2417 VECCREGEXP::iterator expr = stackRegExps.begin();
2419 URIUtils::Split(item1->GetPath(), filePath, file1);
2420 if (URIUtils::HasEncodedFilename(CURL(filePath)))
2421 file1 = CURL::Decode(file1);
2424 while (expr != stackRegExps.end())
2426 if (expr->RegFind(file1, offset) != -1)
2428 std::string Title1 = expr->GetMatch(1),
2429 Volume1 = expr->GetMatch(2),
2430 Ignore1 = expr->GetMatch(3),
2431 Extension1 = expr->GetMatch(4);
2433 Title1 = file1.substr(0, expr->GetSubStart(2));
2437 CFileItemPtr item2 = Get(j);
2439 // skip folders, nfo files, playlists
2440 if (item2->m_bIsFolder
2441 || item2->IsParentFolder()
2443 || item2->IsPlayList()
2451 std::string file2, filePath2;
2452 URIUtils::Split(item2->GetPath(), filePath2, file2);
2453 if (URIUtils::HasEncodedFilename(CURL(filePath2)) )
2454 file2 = CURL::Decode(file2);
2456 if (expr->RegFind(file2, offset) != -1)
2458 std::string Title2 = expr->GetMatch(1),
2459 Volume2 = expr->GetMatch(2),
2460 Ignore2 = expr->GetMatch(3),
2461 Extension2 = expr->GetMatch(4);
2463 Title2 = file2.substr(0, expr->GetSubStart(2));
2464 if (StringUtils::EqualsNoCase(Title1, Title2))
2466 if (!StringUtils::EqualsNoCase(Volume1, Volume2))
2468 if (StringUtils::EqualsNoCase(Ignore1, Ignore2) &&
2469 StringUtils::EqualsNoCase(Extension1, Extension2))
2471 if (stack.size() == 0)
2473 stackName = Title1 + Ignore1 + Extension1;
2475 size += item1->m_dwSize;
2478 size += item2->m_dwSize;
2487 else if (!StringUtils::EqualsNoCase(Ignore1, Ignore2)) // False positive, try again with offset
2489 offset = expr->GetSubStart(3);
2492 else // Extension mismatch
2499 else // Title mismatch
2506 else // No match 2, next expression
2515 expr = stackRegExps.end();
2522 if (stack.size() > 1)
2524 // have a stack, remove the items and add the stacked item
2525 // dont actually stack a multipart rar set, just remove all items but the first
2526 std::string stackPath;
2527 if (Get(stack[0])->IsRAR())
2528 stackPath = Get(stack[0])->GetPath();
2531 CStackDirectory dir;
2532 stackPath = dir.ConstructStackPath(*this, stack);
2534 item1->SetPath(stackPath);
2536 for (unsigned k = 1; k < stack.size(); k++)
2538 // item->m_bIsFolder = true; // don't treat stacked files as folders
2539 // the label may be in a different char set from the filename (eg over smb
2540 // the label is converted from utf8, but the filename is not)
2541 if (!CSettings::Get().GetBool("filelists.showextensions"))
2542 URIUtils::RemoveExtension(stackName);
2544 item1->SetLabel(stackName);
2545 item1->m_dwSize = size;
2553 bool CFileItemList::Load(int windowID)
2556 if (file.Open(GetDiscFileCache(windowID)))
2558 CArchive ar(&file, CArchive::load);
2560 CLog::Log(LOGDEBUG,"Loading items: %i, directory: %s sort method: %i, ascending: %s", Size(), CURL::GetRedacted(GetPath()).c_str(), m_sortDescription.sortBy,
2561 m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false");
2570 bool CFileItemList::Save(int windowID)
2576 CLog::Log(LOGDEBUG,"Saving fileitems [%s]", CURL::GetRedacted(GetPath()).c_str());
2579 if (file.OpenForWrite(GetDiscFileCache(windowID), true)) // overwrite always
2581 CArchive ar(&file, CArchive::store);
2583 CLog::Log(LOGDEBUG," -- items: %i, sort method: %i, ascending: %s", iSize, m_sortDescription.sortBy, m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false");
2592 void CFileItemList::RemoveDiscCache(int windowID) const
2594 std::string cacheFile(GetDiscFileCache(windowID));
2595 if (CFile::Exists(cacheFile))
2597 CLog::Log(LOGDEBUG,"Clearing cached fileitems [%s]",GetPath().c_str());
2598 CFile::Delete(cacheFile);
2602 std::string CFileItemList::GetDiscFileCache(int windowID) const
2604 std::string strPath(GetPath());
2605 URIUtils::RemoveSlashAtEnd(strPath);
2608 crc.ComputeFromLowerCase(strPath);
2610 std::string cacheFile;
2611 if (IsCDDA() || IsOnDVD())
2612 cacheFile = StringUtils::Format("special://temp/r-%08x.fi", (unsigned __int32)crc);
2613 else if (IsMusicDb())
2614 cacheFile = StringUtils::Format("special://temp/mdb-%08x.fi", (unsigned __int32)crc);
2615 else if (IsVideoDb())
2616 cacheFile = StringUtils::Format("special://temp/vdb-%08x.fi", (unsigned __int32)crc);
2617 else if (IsSmartPlayList())
2618 cacheFile = StringUtils::Format("special://temp/sp-%08x.fi", (unsigned __int32)crc);
2620 cacheFile = StringUtils::Format("special://temp/%i-%08x.fi", windowID, (unsigned __int32)crc);
2622 cacheFile = StringUtils::Format("special://temp/%08x.fi", (unsigned __int32)crc);
2626 bool CFileItemList::AlwaysCache() const
2628 // some database folders are always cached
2630 return CMusicDatabaseDirectory::CanCache(GetPath());
2632 return CVideoDatabaseDirectory::CanCache(GetPath());
2634 return true; // always cache
2638 std::string CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */, bool fallbackToFolder /* = false */) const
2640 if (m_strPath.empty()
2641 || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://")
2642 || StringUtils::StartsWithNoCase(m_strPath, "newplaylist://")
2643 || m_bIsShareOrDrive
2644 || IsInternetStream()
2645 || URIUtils::IsUPnP(m_strPath)
2646 || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
2653 // we first check for <filename>.tbn or <foldername>.tbn
2654 std::string fileThumb(GetTBNFile());
2655 if (CFile::Exists(fileThumb))
2658 // Fall back to folder thumb, if requested
2659 if (!m_bIsFolder && fallbackToFolder)
2661 CFileItem item(URIUtils::GetDirectory(m_strPath), true);
2662 return item.GetUserMusicThumb(alwaysCheckRemote);
2665 // if a folder, check for folder.jpg
2666 if (m_bIsFolder && !IsFileFolder() && (!IsRemote() || alwaysCheckRemote || CSettings::Get().GetBool("musicfiles.findremotethumbs")))
2668 vector<string> thumbs = StringUtils::Split(g_advancedSettings.m_musicThumbs, "|");
2669 for (vector<string>::const_iterator i = thumbs.begin(); i != thumbs.end(); ++i)
2671 std::string folderThumb(GetFolderThumb(*i));
2672 if (CFile::Exists(folderThumb))
2682 // Gets the .tbn filename from a file or folder name.
2683 // <filename>.ext -> <filename>.tbn
2684 // <foldername>/ -> <foldername>.tbn
2685 std::string CFileItem::GetTBNFile() const
2687 std::string thumbFile;
2688 std::string strFile = m_strPath;
2692 std::string strPath, strReturn;
2693 URIUtils::GetParentPath(m_strPath,strPath);
2694 CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2695 std::string strTBNFile = item.GetTBNFile();
2696 strReturn = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strTBNFile));
2697 if (CFile::Exists(strReturn))
2700 strFile = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)));
2703 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2705 std::string strPath = URIUtils::GetDirectory(strFile);
2706 std::string strParent;
2707 URIUtils::GetParentPath(strPath,strParent);
2708 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(m_strPath));
2712 strFile = url.GetFileName();
2714 if (m_bIsFolder && !IsFileFolder())
2715 URIUtils::RemoveSlashAtEnd(strFile);
2717 if (!strFile.empty())
2719 if (m_bIsFolder && !IsFileFolder())
2720 thumbFile = strFile + ".tbn"; // folder, so just add ".tbn"
2722 thumbFile = URIUtils::ReplaceExtension(strFile, ".tbn");
2723 url.SetFileName(thumbFile);
2724 thumbFile = url.Get();
2729 bool CFileItem::SkipLocalArt() const
2731 return (m_strPath.empty()
2732 || StringUtils::StartsWithNoCase(m_strPath, "newsmartplaylist://")
2733 || StringUtils::StartsWithNoCase(m_strPath, "newplaylist://")
2734 || m_bIsShareOrDrive
2735 || IsInternetStream()
2736 || URIUtils::IsUPnP(m_strPath)
2737 || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
2745 std::string CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) const
2753 thumb = GetLocalArt(artFile, false);
2754 if (!thumb.empty() && CFile::Exists(thumb))
2757 if ((useFolder || (m_bIsFolder && !IsFileFolder())) && !artFile.empty())
2759 std::string thumb2 = GetLocalArt(artFile, true);
2760 if (!thumb2.empty() && thumb2 != thumb && CFile::Exists(thumb2))
2766 std::string CFileItem::GetLocalArt(const std::string &artFile, bool useFolder) const
2768 // no retrieving of empty art files from folders
2769 if (useFolder && artFile.empty())
2772 std::string strFile = m_strPath;
2775 /* CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2776 std::string localArt = item.GetLocalArt(artFile);
2779 std::string strPath;
2780 URIUtils::GetParentPath(m_strPath,strPath);
2781 strFile = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)));
2784 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2786 std::string strPath = URIUtils::GetDirectory(strFile);
2787 std::string strParent;
2788 URIUtils::GetParentPath(strPath,strParent);
2789 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(strFile));
2793 strFile = CMultiPathDirectory::GetFirstPath(m_strPath);
2795 if (IsOpticalMediaFile())
2796 { // optical media files should be treated like folders
2798 strFile = GetLocalMetadataPath();
2800 else if (useFolder && !(m_bIsFolder && !IsFileFolder()))
2801 strFile = URIUtils::GetDirectory(strFile);
2803 if (strFile.empty()) // empty filepath -> nothing to find
2808 if (!artFile.empty())
2809 return URIUtils::AddFileToFolder(strFile, artFile);
2813 if (artFile.empty()) // old thumbnail matching
2814 return URIUtils::ReplaceExtension(strFile, ".tbn");
2816 return URIUtils::ReplaceExtension(strFile, "-" + artFile);
2821 std::string CFileItem::GetFolderThumb(const std::string &folderJPG /* = "folder.jpg" */) const
2823 std::string strFolder = m_strPath;
2826 URIUtils::IsInRAR(strFolder) ||
2827 URIUtils::IsInZIP(strFolder))
2829 URIUtils::GetParentPath(m_strPath,strFolder);
2833 strFolder = CMultiPathDirectory::GetFirstPath(m_strPath);
2835 return URIUtils::AddFileToFolder(strFolder, folderJPG);
2838 std::string CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const
2840 if (IsLabelPreformated())
2843 if (m_pvrRecordingInfoTag)
2844 return m_pvrRecordingInfoTag->m_strTitle;
2845 else if (CUtil::IsTVRecording(m_strPath))
2847 std::string title = CPVRRecording::GetTitleFromURL(m_strPath);
2852 std::string strMovieName = GetBaseMoviePath(bUseFolderNames);
2854 if (URIUtils::IsStack(strMovieName))
2855 strMovieName = CStackDirectory::GetStackedTitlePath(strMovieName);
2857 URIUtils::RemoveSlashAtEnd(strMovieName);
2859 return CURL::Decode(URIUtils::GetFileName(strMovieName));
2862 std::string CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
2864 std::string strMovieName = m_strPath;
2867 strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
2869 if (IsOpticalMediaFile())
2870 return GetLocalMetadataPath();
2872 if ((!m_bIsFolder || URIUtils::IsInArchive(m_strPath)) && bUseFolderNames)
2874 std::string name2(strMovieName);
2875 URIUtils::GetParentPath(name2,strMovieName);
2876 if (URIUtils::IsInArchive(m_strPath))
2878 std::string strArchivePath;
2879 URIUtils::GetParentPath(strMovieName, strArchivePath);
2880 strMovieName = strArchivePath;
2884 return strMovieName;
2887 std::string CFileItem::GetLocalFanart() const
2891 if (!HasVideoInfoTag())
2892 return ""; // nothing can be done
2893 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
2894 return dbItem.GetLocalFanart();
2897 std::string strFile2;
2898 std::string strFile = m_strPath;
2901 std::string strPath;
2902 URIUtils::GetParentPath(m_strPath,strPath);
2903 CStackDirectory dir;
2904 std::string strPath2;
2905 strPath2 = dir.GetStackedTitlePath(strFile);
2906 strFile = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strPath2));
2907 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
2908 std::string strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-fanart"));
2909 strFile2 = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(strTBNFile));
2911 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2913 std::string strPath = URIUtils::GetDirectory(strFile);
2914 std::string strParent;
2915 URIUtils::GetParentPath(strPath,strParent);
2916 strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(m_strPath));
2919 // no local fanart available for these
2920 if (IsInternetStream()
2921 || URIUtils::IsUPnP(strFile)
2922 || URIUtils::IsBluray(strFile)
2927 || (URIUtils::IsFTP(strFile) && !g_advancedSettings.m_bFTPThumbs)
2928 || m_strPath.empty())
2931 std::string strDir = URIUtils::GetDirectory(strFile);
2936 CFileItemList items;
2937 CDirectory::GetDirectory(strDir, items, g_advancedSettings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
2938 if (IsOpticalMediaFile())
2939 { // grab from the optical media parent folder as well
2940 CFileItemList moreItems;
2941 CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems, g_advancedSettings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
2942 items.Append(moreItems);
2945 vector<string> fanarts = StringUtils::Split(g_advancedSettings.m_fanartImages, "|");
2947 strFile = URIUtils::ReplaceExtension(strFile, "-fanart");
2948 fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile));
2950 if (!strFile2.empty())
2951 fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile2));
2953 for (vector<string>::const_iterator i = fanarts.begin(); i != fanarts.end(); ++i)
2955 for (int j = 0; j < items.Size(); j++)
2957 std::string strCandidate = URIUtils::GetFileName(items[j]->m_strPath);
2958 URIUtils::RemoveExtension(strCandidate);
2959 std::string strFanart = *i;
2960 URIUtils::RemoveExtension(strFanart);
2961 if (StringUtils::EqualsNoCase(strCandidate, strFanart))
2962 return items[j]->m_strPath;
2969 std::string CFileItem::GetLocalMetadataPath() const
2971 if (m_bIsFolder && !IsFileFolder())
2974 std::string parent(URIUtils::GetParentPath(m_strPath));
2975 std::string parentFolder(parent);
2976 URIUtils::RemoveSlashAtEnd(parentFolder);
2977 parentFolder = URIUtils::GetFileName(parentFolder);
2978 if (StringUtils::EqualsNoCase(parentFolder, "VIDEO_TS") || StringUtils::EqualsNoCase(parentFolder, "BDMV"))
2979 { // go back up another one
2980 parent = URIUtils::GetParentPath(parent);
2985 bool CFileItem::LoadMusicTag()
2991 if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
2994 CMusicDatabase musicDatabase;
2995 if (musicDatabase.Open())
2998 if (musicDatabase.GetSongByFileName(m_strPath, song))
3000 GetMusicInfoTag()->SetSong(song);
3001 SetArt("thumb", song.strThumb);
3004 musicDatabase.Close();
3006 // load tag from file
3007 CLog::Log(LOGDEBUG, "%s: loading tag information for file: %s", __FUNCTION__, m_strPath.c_str());
3008 CMusicInfoTagLoaderFactory factory;
3009 auto_ptr<IMusicInfoTagLoader> pLoader (factory.CreateLoader(m_strPath));
3010 if (NULL != pLoader.get())
3012 if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
3015 // no tag - try some other things
3018 // we have the tracknumber...
3019 int iTrack = GetMusicInfoTag()->GetTrackNumber();
3022 std::string strText = g_localizeStrings.Get(554); // "Track"
3023 if (!strText.empty() && strText[strText.size() - 1] != ' ')
3025 std::string strTrack = StringUtils::Format((strText + "%i").c_str(), iTrack);
3026 GetMusicInfoTag()->SetTitle(strTrack);
3027 GetMusicInfoTag()->SetLoaded(true);
3033 std::string fileName = URIUtils::GetFileName(m_strPath);
3034 URIUtils::RemoveExtension(fileName);
3035 for (unsigned int i = 0; i < g_advancedSettings.m_musicTagsFromFileFilters.size(); i++)
3037 CLabelFormatter formatter(g_advancedSettings.m_musicTagsFromFileFilters[i], "");
3038 if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
3040 GetMusicInfoTag()->SetLoaded(true);
3048 void CFileItemList::Swap(unsigned int item1, unsigned int item2)
3050 if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size())
3051 std::swap(m_items[item1], m_items[item2]);
3054 bool CFileItemList::UpdateItem(const CFileItem *item)
3056 if (!item) return false;
3058 CSingleLock lock(m_lock);
3059 for (unsigned int i = 0; i < m_items.size(); i++)
3061 CFileItemPtr pItem = m_items[i];
3062 if (pItem->IsSamePath(item))
3064 pItem->UpdateInfo(*item);
3071 void CFileItemList::AddSortMethod(SortBy sortBy, int buttonLabel, const LABEL_MASKS &labelMasks, SortAttribute sortAttributes /* = SortAttributeNone */)
3073 AddSortMethod(sortBy, sortAttributes, buttonLabel, labelMasks);
3076 void CFileItemList::AddSortMethod(SortBy sortBy, SortAttribute sortAttributes, int buttonLabel, const LABEL_MASKS &labelMasks)
3078 SortDescription sorting;
3079 sorting.sortBy = sortBy;
3080 sorting.sortAttributes = sortAttributes;
3082 AddSortMethod(sorting, buttonLabel, labelMasks);
3085 void CFileItemList::AddSortMethod(SortDescription sortDescription, int buttonLabel, const LABEL_MASKS &labelMasks)
3087 SORT_METHOD_DETAILS sort;
3088 sort.m_sortDescription = sortDescription;
3089 sort.m_buttonLabel = buttonLabel;
3090 sort.m_labelMasks = labelMasks;
3092 m_sortDetails.push_back(sort);
3095 void CFileItemList::SetReplaceListing(bool replace)
3097 m_replaceListing = replace;
3100 void CFileItemList::ClearSortState()
3102 m_sortDescription.sortBy = SortByNone;
3103 m_sortDescription.sortOrder = SortOrderNone;
3104 m_sortDescription.sortAttributes = SortAttributeNone;
3107 CVideoInfoTag* CFileItem::GetVideoInfoTag()
3109 if (!m_videoInfoTag)
3110 m_videoInfoTag = new CVideoInfoTag;
3112 return m_videoInfoTag;
3115 CEpgInfoTag* CFileItem::GetEPGInfoTag()
3118 m_epgInfoTag = new CEpgInfoTag;
3120 return m_epgInfoTag;
3123 CPVRChannel* CFileItem::GetPVRChannelInfoTag()
3125 if (!m_pvrChannelInfoTag)
3126 m_pvrChannelInfoTag = new CPVRChannel;
3128 return m_pvrChannelInfoTag;
3131 CPVRRecording* CFileItem::GetPVRRecordingInfoTag()
3133 if (!m_pvrRecordingInfoTag)
3134 m_pvrRecordingInfoTag = new CPVRRecording;
3136 return m_pvrRecordingInfoTag;
3139 CPVRTimerInfoTag* CFileItem::GetPVRTimerInfoTag()
3141 if (!m_pvrTimerInfoTag)
3142 m_pvrTimerInfoTag = new CPVRTimerInfoTag;
3144 return m_pvrTimerInfoTag;
3147 CPictureInfoTag* CFileItem::GetPictureInfoTag()
3149 if (!m_pictureInfoTag)
3150 m_pictureInfoTag = new CPictureInfoTag;
3152 return m_pictureInfoTag;
3155 MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
3157 if (!m_musicInfoTag)
3158 m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
3160 return m_musicInfoTag;
3163 std::string CFileItem::FindTrailer() const
3165 std::string strFile2;
3166 std::string strFile = m_strPath;
3169 std::string strPath;
3170 URIUtils::GetParentPath(m_strPath,strPath);
3171 CStackDirectory dir;
3172 std::string strPath2;
3173 strPath2 = dir.GetStackedTitlePath(strFile);
3174 strFile = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2));
3175 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
3176 std::string strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-trailer"));
3177 strFile2 = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile));
3179 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
3181 std::string strPath = URIUtils::GetDirectory(strFile);
3182 std::string strParent;
3183 URIUtils::GetParentPath(strPath,strParent);
3184 strFile = URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath));
3187 // no local trailer available for these
3188 if (IsInternetStream()
3189 || URIUtils::IsUPnP(strFile)
3190 || URIUtils::IsBluray(strFile)
3196 std::string strDir = URIUtils::GetDirectory(strFile);
3197 CFileItemList items;
3198 CDirectory::GetDirectory(strDir, items, g_advancedSettings.m_videoExtensions, DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO | DIR_FLAG_NO_FILE_DIRS);
3199 URIUtils::RemoveExtension(strFile);
3200 strFile += "-trailer";
3201 std::string strFile3 = URIUtils::AddFileToFolder(strDir, "movie-trailer");
3203 // Precompile our REs
3204 VECCREGEXP matchRegExps;
3205 CRegExp tmpRegExp(true, CRegExp::autoUtf8);
3206 const vector<string>& strMatchRegExps = g_advancedSettings.m_trailerMatchRegExps;
3208 vector<string>::const_iterator strRegExp = strMatchRegExps.begin();
3209 while (strRegExp != strMatchRegExps.end())
3211 if (tmpRegExp.RegComp(*strRegExp))
3213 matchRegExps.push_back(tmpRegExp);
3218 std::string strTrailer;
3219 for (int i = 0; i < items.Size(); i++)
3221 std::string strCandidate = items[i]->m_strPath;
3222 URIUtils::RemoveExtension(strCandidate);
3223 if (StringUtils::EqualsNoCase(strCandidate, strFile) ||
3224 StringUtils::EqualsNoCase(strCandidate, strFile2) ||
3225 StringUtils::EqualsNoCase(strCandidate, strFile3))
3227 strTrailer = items[i]->m_strPath;
3232 VECCREGEXP::iterator expr = matchRegExps.begin();
3234 while (expr != matchRegExps.end())
3236 if (expr->RegFind(strCandidate) != -1)
3238 strTrailer = items[i]->m_strPath;
3250 int CFileItem::GetVideoContentType() const
3252 VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
3253 if (HasVideoInfoTag() && !GetVideoInfoTag()->m_strShowTitle.empty()) // tvshow
3254 type = VIDEODB_CONTENT_TVSHOWS;
3255 if (HasVideoInfoTag() && GetVideoInfoTag()->m_iSeason > -1 && !m_bIsFolder) // episode
3256 return VIDEODB_CONTENT_EPISODES;
3257 if (HasVideoInfoTag() && !GetVideoInfoTag()->m_artist.empty()) // music video
3258 return VIDEODB_CONTENT_MUSICVIDEOS;
3260 CVideoDatabaseDirectory dir;
3261 VIDEODATABASEDIRECTORY::CQueryParams params;
3262 dir.GetQueryParams(m_strPath, params);
3263 if (params.GetSetId() != -1 && params.GetMovieId() == -1) // movie set
3264 return VIDEODB_CONTENT_MOVIE_SETS;
3269 bool CFileItem::IsResumePointSet() const
3271 return (HasVideoInfoTag() && GetVideoInfoTag()->m_resumePoint.IsSet()) ||
3272 (HasPVRRecordingInfoTag() && GetPVRRecordingInfoTag()->GetLastPlayedPosition() > 0);
3275 double CFileItem::GetCurrentResumeTime() const
3277 if (HasPVRRecordingInfoTag())
3279 // This will retrieve 'fresh' resume information from the PVR server
3280 int rc = GetPVRRecordingInfoTag()->GetLastPlayedPosition();
3283 // Fall through to default value
3285 if (HasVideoInfoTag() && GetVideoInfoTag()->m_resumePoint.IsSet())
3287 return GetVideoInfoTag()->m_resumePoint.timeInSeconds;
3289 // Resume from start when resume points are invalid or the PVR server returns an error