2 * Copyright (C) 2005-2008 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, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
23 #include "guilib/LocalizeStrings.h"
24 #include "utils/StringUtils.h"
25 #include "utils/URIUtils.h"
27 #include "pictures/Picture.h"
28 #include "playlists/PlayListFactory.h"
29 #include "utils/Crc32.h"
30 #include "filesystem/DirectoryCache.h"
31 #include "filesystem/StackDirectory.h"
32 #include "filesystem/FileCurl.h"
33 #include "filesystem/MultiPathDirectory.h"
34 #include "filesystem/MusicDatabaseDirectory.h"
35 #include "filesystem/VideoDatabaseDirectory.h"
36 #include "filesystem/FactoryDirectory.h"
37 #include "music/tags/MusicInfoTagLoaderFactory.h"
38 #include "CueDocument.h"
39 #include "video/VideoDatabase.h"
40 #include "music/MusicDatabase.h"
41 #include "SortFileItem.h"
42 #include "utils/TuxBoxUtil.h"
43 #include "video/VideoInfoTag.h"
44 #include "threads/SingleLock.h"
45 #include "music/tags/MusicInfoTag.h"
46 #include "pictures/PictureInfoTag.h"
47 #include "music/Artist.h"
48 #include "music/Album.h"
49 #include "music/Song.h"
51 #include "settings/GUISettings.h"
52 #include "settings/AdvancedSettings.h"
53 #include "settings/Settings.h"
54 #include "utils/RegExp.h"
55 #include "utils/log.h"
56 #include "utils/Variant.h"
57 #include "music/karaoke/karaokelyricsfactory.h"
60 using namespace XFILE;
61 using namespace PLAYLIST;
62 using namespace MUSIC_INFO;
64 CFileItem::CFileItem(const CSong& song)
66 m_musicInfoTag = NULL;
67 m_videoInfoTag = NULL;
68 m_pictureInfoTag = NULL;
70 SetLabel(song.strTitle);
71 m_strPath = song.strFileName;
72 GetMusicInfoTag()->SetSong(song);
73 m_lStartOffset = song.iStartOffset;
74 m_lEndOffset = song.iEndOffset;
75 m_strThumbnailImage = song.strThumb;
78 CFileItem::CFileItem(const CStdString &path, const CAlbum& album)
80 m_musicInfoTag = NULL;
81 m_videoInfoTag = NULL;
82 m_pictureInfoTag = NULL;
84 SetLabel(album.strAlbum);
87 m_strLabel2 = album.strArtist;
88 URIUtils::AddSlashAtEnd(m_strPath);
89 GetMusicInfoTag()->SetAlbum(album);
90 if (album.thumbURL.m_url.size() > 0)
91 m_strThumbnailImage = album.thumbURL.m_url[0].m_url;
93 m_strThumbnailImage.clear();
95 CMusicDatabase::SetPropertiesFromAlbum(*this,album);
98 CFileItem::CFileItem(const CVideoInfoTag& movie)
100 m_musicInfoTag = NULL;
101 m_videoInfoTag = NULL;
102 m_pictureInfoTag = NULL;
104 SetLabel(movie.m_strTitle);
105 if (movie.m_strFileNameAndPath.IsEmpty())
107 m_strPath = movie.m_strPath;
108 URIUtils::AddSlashAtEnd(m_strPath);
113 m_strPath = movie.m_strFileNameAndPath;
116 *GetVideoInfoTag() = movie;
118 SetCachedVideoThumb();
121 CFileItem::CFileItem(const CArtist& artist)
123 m_musicInfoTag = NULL;
124 m_videoInfoTag = NULL;
125 m_pictureInfoTag = NULL;
127 SetLabel(artist.strArtist);
128 m_strPath = artist.strArtist;
130 URIUtils::AddSlashAtEnd(m_strPath);
131 GetMusicInfoTag()->SetArtist(artist.strArtist);
134 CFileItem::CFileItem(const CGenre& genre)
136 m_musicInfoTag = NULL;
137 m_videoInfoTag = NULL;
138 m_pictureInfoTag = NULL;
140 SetLabel(genre.strGenre);
141 m_strPath = genre.strGenre;
143 URIUtils::AddSlashAtEnd(m_strPath);
144 GetMusicInfoTag()->SetGenre(genre.strGenre);
147 CFileItem::CFileItem(const CFileItem& item): CGUIListItem()
149 m_musicInfoTag = NULL;
150 m_videoInfoTag = NULL;
151 m_pictureInfoTag = NULL;
155 CFileItem::CFileItem(const CGUIListItem& item)
157 m_musicInfoTag = NULL;
158 m_videoInfoTag = NULL;
159 m_pictureInfoTag = NULL;
161 // not particularly pretty, but it gets around the issue of Reset() defaulting
162 // parameters in the CGUIListItem base class.
163 *((CGUIListItem *)this) = item;
166 CFileItem::CFileItem(void)
168 m_musicInfoTag = NULL;
169 m_videoInfoTag = NULL;
170 m_pictureInfoTag = NULL;
174 CFileItem::CFileItem(const CStdString& strLabel)
177 m_musicInfoTag = NULL;
178 m_videoInfoTag = NULL;
179 m_pictureInfoTag = NULL;
184 CFileItem::CFileItem(const CStdString& strPath, bool bIsFolder)
186 m_musicInfoTag = NULL;
187 m_videoInfoTag = NULL;
188 m_pictureInfoTag = NULL;
191 m_bIsFolder = bIsFolder;
192 // tuxbox urls cannot have a / at end
193 if (m_bIsFolder && !m_strPath.IsEmpty() && !IsFileFolder() && !URIUtils::IsTuxBox(m_strPath))
194 URIUtils::AddSlashAtEnd(m_strPath);
197 CFileItem::CFileItem(const CMediaSource& share)
199 m_musicInfoTag = NULL;
200 m_videoInfoTag = NULL;
201 m_pictureInfoTag = NULL;
204 m_bIsShareOrDrive = true;
205 m_strPath = share.strPath;
206 URIUtils::AddSlashAtEnd(m_strPath);
207 CStdString label = share.strName;
208 if (!share.strStatus.IsEmpty())
209 label.Format("%s (%s)", share.strName.c_str(), share.strStatus.c_str());
211 m_iLockMode = share.m_iLockMode;
212 m_strLockCode = share.m_strLockCode;
213 m_iHasLock = share.m_iHasLock;
214 m_iBadPwdCount = share.m_iBadPwdCount;
215 m_iDriveType = share.m_iDriveType;
216 m_strThumbnailImage = share.m_strThumbnailImage;
217 SetLabelPreformated(true);
220 CFileItem::~CFileItem(void)
222 delete m_musicInfoTag;
223 delete m_videoInfoTag;
224 delete m_pictureInfoTag;
226 m_musicInfoTag = NULL;
227 m_videoInfoTag = NULL;
228 m_pictureInfoTag = NULL;
231 const CFileItem& CFileItem::operator=(const CFileItem& item)
233 if (this == &item) return * this;
234 CGUIListItem::operator=(item);
235 m_bLabelPreformated=item.m_bLabelPreformated;
237 m_strPath = item.m_strPath;
238 m_bIsParentFolder = item.m_bIsParentFolder;
239 m_iDriveType = item.m_iDriveType;
240 m_bIsShareOrDrive = item.m_bIsShareOrDrive;
241 m_dateTime = item.m_dateTime;
242 m_dwSize = item.m_dwSize;
243 if (item.HasMusicInfoTag())
245 m_musicInfoTag = GetMusicInfoTag();
247 *m_musicInfoTag = *item.m_musicInfoTag;
251 delete m_musicInfoTag;
252 m_musicInfoTag = NULL;
255 if (item.HasVideoInfoTag())
257 m_videoInfoTag = GetVideoInfoTag();
259 *m_videoInfoTag = *item.m_videoInfoTag;
263 delete m_videoInfoTag;
264 m_videoInfoTag = NULL;
267 if (item.HasPictureInfoTag())
269 m_pictureInfoTag = GetPictureInfoTag();
270 if (m_pictureInfoTag)
271 *m_pictureInfoTag = *item.m_pictureInfoTag;
275 delete m_pictureInfoTag;
276 m_pictureInfoTag = NULL;
279 m_lStartOffset = item.m_lStartOffset;
280 m_lEndOffset = item.m_lEndOffset;
281 m_strDVDLabel = item.m_strDVDLabel;
282 m_strTitle = item.m_strTitle;
283 m_iprogramCount = item.m_iprogramCount;
284 m_idepth = item.m_idepth;
285 m_iLockMode = item.m_iLockMode;
286 m_strLockCode = item.m_strLockCode;
287 m_iHasLock = item.m_iHasLock;
288 m_iBadPwdCount = item.m_iBadPwdCount;
289 m_bCanQueue=item.m_bCanQueue;
290 m_mimetype = item.m_mimetype;
291 m_extrainfo = item.m_extrainfo;
292 m_specialSort = item.m_specialSort;
296 void CFileItem::Reset()
300 m_bLabelPreformated=false;
302 m_overlayIcon = ICON_OVERLAY_NONE;
305 m_strDVDLabel.Empty();
310 m_bIsParentFolder=false;
311 m_bIsShareOrDrive = false;
313 m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
318 m_iLockMode = LOCK_MODE_EVERYONE;
324 delete m_musicInfoTag;
326 delete m_videoInfoTag;
328 delete m_pictureInfoTag;
329 m_pictureInfoTag=NULL;
331 m_specialSort = SORT_NORMALLY;
335 void CFileItem::Archive(CArchive& ar)
337 CGUIListItem::Archive(ar);
341 ar << m_bIsParentFolder;
342 ar << m_bLabelPreformated;
344 ar << m_bIsShareOrDrive;
350 ar << m_iprogramCount;
352 ar << m_lStartOffset;
356 ar << m_iBadPwdCount;
366 ar << *m_musicInfoTag;
373 ar << *m_videoInfoTag;
377 if (m_pictureInfoTag)
380 ar << *m_pictureInfoTag;
387 ar >> m_bIsParentFolder;
388 ar >> m_bLabelPreformated;
390 ar >> m_bIsShareOrDrive;
396 ar >> m_iprogramCount;
398 ar >> m_lStartOffset;
402 m_iLockMode = (LockType)temp;
404 ar >> m_iBadPwdCount;
410 m_specialSort = (SPECIAL_SORT)temp;
415 ar >> *GetMusicInfoTag();
418 ar >> *GetVideoInfoTag();
421 ar >> *GetPictureInfoTag();
426 void CFileItem::Serialize(CVariant& value)
428 //CGUIListItem::Serialize(value["CGUIListItem"]);
430 value["strPath"] = m_strPath;
431 value["dateTime"] = (m_dateTime.IsValid()) ? m_dateTime.GetAsRFC1123DateTime() : "";
432 value["size"] = (int) m_dwSize / 1000;
433 value["DVDLabel"] = m_strDVDLabel;
434 value["title"] = m_strTitle;
435 value["mimetype"] = m_mimetype;
436 value["extrainfo"] = m_extrainfo;
439 (*m_musicInfoTag).Serialize(value["musicInfoTag"]);
442 (*m_videoInfoTag).Serialize(value["videoInfoTag"]);
444 if (m_pictureInfoTag)
445 (*m_pictureInfoTag).Serialize(value["pictureInfoTag"]);
447 bool CFileItem::Exists(bool bUseCache /* = true */) const
449 if (m_strPath.IsEmpty()
450 || m_strPath.Equals("add")
451 || IsInternetStream()
453 || IsVirtualDirectoryRoot()
457 if (IsVideoDb() && HasVideoInfoTag())
459 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
460 return dbItem.Exists();
463 CStdString strPath = m_strPath;
465 if (URIUtils::IsMultiPath(strPath))
466 strPath = CMultiPathDirectory::GetFirstPath(strPath);
468 if (URIUtils::IsStack(strPath))
469 strPath = CStackDirectory::GetFirstStackedFile(strPath);
472 return CDirectory::Exists(strPath);
474 return CFile::Exists(strPath, bUseCache);
479 bool CFileItem::IsVideo() const
481 /* check preset mime type */
482 if( m_mimetype.Left(6).Equals("video/") )
485 if (HasVideoInfoTag()) return true;
486 if (HasMusicInfoTag()) return false;
487 if (HasPictureInfoTag()) return false;
489 if (IsHDHomeRun() || IsTuxBox() || URIUtils::IsDVD(m_strPath))
492 CStdString extension;
493 if( m_mimetype.Left(12).Equals("application/") )
494 { /* check for some standard types */
495 extension = m_mimetype.Mid(12);
496 if( extension.Equals("ogg")
497 || extension.Equals("mp4")
498 || extension.Equals("mxf") )
502 URIUtils::GetExtension(m_strPath, extension);
504 if (extension.IsEmpty())
509 return (g_settings.m_videoExtensions.Find(extension) != -1);
512 bool CFileItem::IsDiscStub() const
514 CStdString strExtension;
515 URIUtils::GetExtension(m_strPath, strExtension);
517 if (strExtension.IsEmpty())
520 strExtension.ToLower();
523 return (g_settings.m_discStubExtensions + '|').Find(strExtension) != -1;
526 bool CFileItem::IsAudio() const
528 /* check preset mime type */
529 if( m_mimetype.Left(6).Equals("audio/") )
532 if (HasMusicInfoTag()) return true;
533 if (HasVideoInfoTag()) return false;
534 if (HasPictureInfoTag()) return false;
535 if (IsCDDA()) return true;
536 if (!m_bIsFolder && IsLastFM()) return true;
538 CStdString extension;
539 if( m_mimetype.Left(12).Equals("application/") )
540 { /* check for some standard types */
541 extension = m_mimetype.Mid(12);
542 if( extension.Equals("ogg")
543 || extension.Equals("mp4")
544 || extension.Equals("mxf") )
548 URIUtils::GetExtension(m_strPath, extension);
550 if (extension.IsEmpty())
555 return (g_settings.m_musicExtensions.Find(extension) != -1);
558 bool CFileItem::IsKaraoke() const
560 if ( !IsAudio() || IsLastFM())
563 return CKaraokeLyricsFactory::HasLyrics( m_strPath );
566 bool CFileItem::IsPicture() const
568 if( m_mimetype.Left(6).Equals("image/") )
571 if (HasPictureInfoTag()) return true;
572 if (HasMusicInfoTag()) return false;
573 if (HasVideoInfoTag()) return false;
575 return CUtil::IsPicture(m_strPath);
578 bool CFileItem::IsLyrics() const
580 return URIUtils::GetExtension(m_strPath).Equals(".cdg", false) || URIUtils::GetExtension(m_strPath).Equals(".lrc", false);
583 bool CFileItem::IsCUESheet() const
585 return URIUtils::GetExtension(m_strPath).Equals(".cue", false);
588 bool CFileItem::IsLastFM() const
590 return URIUtils::IsLastFM(m_strPath);
593 bool CFileItem::IsInternetStream() const
595 if (HasProperty("IsHTTPDirectory"))
598 return URIUtils::IsInternetStream(m_strPath);
601 bool CFileItem::IsFileFolder() const
605 (IsPlayList() && g_advancedSettings.m_playlistAsFolders) ||
617 bool CFileItem::IsSmartPlayList() const
619 CStdString strExtension;
620 URIUtils::GetExtension(m_strPath, strExtension);
621 strExtension.ToLower();
622 return (strExtension == ".xsp");
625 bool CFileItem::IsPlayList() const
627 return CPlayListFactory::IsPlaylist(*this);
630 bool CFileItem::IsPythonScript() const
632 return URIUtils::GetExtension(m_strPath).Equals(".py", false);
635 bool CFileItem::IsXBE() const
637 return URIUtils::GetExtension(m_strPath).Equals(".xbe", false);
640 bool CFileItem::IsType(const char *ext) const
642 return URIUtils::GetExtension(m_strPath).Equals(ext, false);
645 bool CFileItem::IsShortCut() const
647 return URIUtils::GetExtension(m_strPath).Equals(".cut", false);
650 bool CFileItem::IsNFO() const
652 return URIUtils::GetExtension(m_strPath).Equals(".nfo", false);
655 bool CFileItem::IsDVDImage() const
657 CStdString strExtension;
658 URIUtils::GetExtension(m_strPath, strExtension);
659 return (strExtension.Equals(".img") || strExtension.Equals(".iso") || strExtension.Equals(".nrg"));
662 bool CFileItem::IsOpticalMediaFile() const
664 bool found = IsDVDFile(false, true);
670 bool CFileItem::IsDVDFile(bool bVobs /*= true*/, bool bIfos /*= true*/) const
672 CStdString strFileName = URIUtils::GetFileName(m_strPath);
675 if (strFileName.Equals("video_ts.ifo")) return true;
676 if (strFileName.Left(4).Equals("vts_") && strFileName.Right(6).Equals("_0.ifo") && strFileName.length() == 12) return true;
680 if (strFileName.Equals("video_ts.vob")) return true;
681 if (strFileName.Left(4).Equals("vts_") && strFileName.Right(4).Equals(".vob")) return true;
687 bool CFileItem::IsBDFile() const
689 CStdString strFileName = URIUtils::GetFileName(m_strPath);
690 return (strFileName.Equals("index.bdmv"));
693 bool CFileItem::IsRAR() const
695 return URIUtils::IsRAR(m_strPath);
698 bool CFileItem::IsZIP() const
700 return URIUtils::IsZIP(m_strPath);
703 bool CFileItem::IsCBZ() const
705 return URIUtils::GetExtension(m_strPath).Equals(".cbz", false);
708 bool CFileItem::IsCBR() const
710 return URIUtils::GetExtension(m_strPath).Equals(".cbr", false);
713 bool CFileItem::IsRSS() const
715 if (m_strPath.Left(6).Equals("rss://"))
718 return URIUtils::GetExtension(m_strPath).Equals(".rss")
719 || GetMimeType() == "application/rss+xml";
722 bool CFileItem::IsStack() const
724 return URIUtils::IsStack(m_strPath);
727 bool CFileItem::IsPlugin() const
729 return URIUtils::IsPlugin(m_strPath);
732 bool CFileItem::IsAddonsPath() const
734 return URIUtils::IsAddonsPath(m_strPath);
737 bool CFileItem::IsMultiPath() const
739 return URIUtils::IsMultiPath(m_strPath);
742 bool CFileItem::IsCDDA() const
744 return URIUtils::IsCDDA(m_strPath);
747 bool CFileItem::IsDVD() const
749 return URIUtils::IsDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
752 bool CFileItem::IsOnDVD() const
754 return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
757 bool CFileItem::IsOnLAN() const
759 return URIUtils::IsOnLAN(m_strPath);
762 bool CFileItem::IsISO9660() const
764 return URIUtils::IsISO9660(m_strPath);
767 bool CFileItem::IsRemote() const
769 return URIUtils::IsRemote(m_strPath);
772 bool CFileItem::IsSmb() const
774 return URIUtils::IsSmb(m_strPath);
777 bool CFileItem::IsURL() const
779 return URIUtils::IsURL(m_strPath);
782 bool CFileItem::IsDAAP() const
784 return URIUtils::IsDAAP(m_strPath);
787 bool CFileItem::IsTuxBox() const
789 return URIUtils::IsTuxBox(m_strPath);
792 bool CFileItem::IsMythTV() const
794 return URIUtils::IsMythTV(m_strPath);
797 bool CFileItem::IsHDHomeRun() const
799 return URIUtils::IsHDHomeRun(m_strPath);
802 bool CFileItem::IsVTP() const
804 return URIUtils::IsVTP(m_strPath);
807 bool CFileItem::IsLiveTV() const
809 return URIUtils::IsLiveTV(m_strPath);
812 bool CFileItem::IsHD() const
814 return URIUtils::IsHD(m_strPath);
817 bool CFileItem::IsMusicDb() const
820 return url.GetProtocol().Equals("musicdb");
823 bool CFileItem::IsVideoDb() const
826 return url.GetProtocol().Equals("videodb");
829 bool CFileItem::IsVirtualDirectoryRoot() const
831 return (m_bIsFolder && m_strPath.IsEmpty());
834 bool CFileItem::IsRemovable() const
836 return IsOnDVD() || IsCDDA() || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE;
839 bool CFileItem::IsReadOnly() const
841 if (IsParentFolder()) return true;
842 if (m_bIsShareOrDrive) return true;
843 return !CUtil::SupportsFileOperations(m_strPath);
846 void CFileItem::FillInDefaultIcon()
848 //CLog::Log(LOGINFO, "FillInDefaultIcon(%s)", pItem->GetLabel().c_str());
849 // find the default icon for a file or folder item
850 // for files this can be the (depending on the file type)
851 // default picture for photo's
852 // default picture for songs
853 // default picture for videos
854 // default picture for shortcuts
855 // default picture for playlists
856 // or the icon embedded in an .xbe
859 // for .. folders the default picture for parent folder
860 // for other folders the defaultFolder.png
862 if (GetIconImage().IsEmpty())
866 /* To reduce the average runtime of this code, this list should
867 * be ordered with most frequently seen types first. Also bear
868 * in mind the complexity of the code behind the check in the
869 * case of IsWhatater() returns false.
874 SetIconImage("DefaultAudio.png");
876 else if ( IsVideo() )
879 SetIconImage("DefaultVideo.png");
881 else if ( IsPicture() )
884 SetIconImage("DefaultPicture.png");
886 else if ( IsPlayList() )
888 SetIconImage("DefaultPlaylist.png");
893 SetIconImage("DefaultProgram.png");
895 else if ( IsShortCut() && !IsLabelPreformated() )
898 CStdString strFName = URIUtils::GetFileName(m_strPath);
899 int iPos = strFName.ReverseFind(".");
900 CStdString strDescription = strFName.Left(iPos);
901 SetLabel(strDescription);
902 SetIconImage("DefaultShortcut.png");
904 else if ( IsPythonScript() )
906 SetIconImage("DefaultScript.png");
910 // default icon for unknown file type
911 SetIconImage("DefaultFile.png");
918 SetIconImage("DefaultPlaylist.png");
920 else if (IsParentFolder())
922 SetIconImage("DefaultFolderBack.png");
926 SetIconImage("DefaultFolder.png");
930 // Set the icon overlays (if applicable)
933 if (URIUtils::IsInRAR(m_strPath))
934 SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR);
935 else if (URIUtils::IsInZIP(m_strPath))
936 SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP);
940 CStdString CFileItem::GetCachedArtistThumb() const
942 return GetCachedThumb("artist"+GetLabel(),g_settings.GetMusicArtistThumbFolder());
945 CStdString CFileItem::GetCachedSeasonThumb() const
947 CStdString seasonPath;
948 if (HasVideoInfoTag())
949 seasonPath = GetVideoInfoTag()->m_strPath;
951 return GetCachedThumb("season"+seasonPath+GetLabel(),g_settings.GetVideoThumbFolder(),true);
954 CStdString CFileItem::GetCachedActorThumb() const
956 return GetCachedThumb("actor"+GetLabel(),g_settings.GetVideoThumbFolder(),true);
959 void CFileItem::SetCachedArtistThumb()
961 CStdString thumb(GetCachedArtistThumb());
962 if (CFile::Exists(thumb))
964 // found it, we are finished.
965 SetThumbnailImage(thumb);
969 // set the album thumb for a file or folder
970 void CFileItem::SetMusicThumb(bool alwaysCheckRemote /* = true */)
972 if (HasThumbnail()) return;
974 SetCachedMusicThumb();
976 SetUserMusicThumb(alwaysCheckRemote);
979 void CFileItem::SetCachedSeasonThumb()
981 CStdString thumb(GetCachedSeasonThumb());
982 if (CFile::Exists(thumb))
984 // found it, we are finished.
985 SetThumbnailImage(thumb);
989 void CFileItem::RemoveExtension()
993 CStdString strLabel = GetLabel();
994 URIUtils::RemoveExtension(strLabel);
998 void CFileItem::CleanString()
1003 bool bIsFolder = m_bIsFolder;
1005 // make sure we don't append the extension to stacked dvd folders
1006 if (HasProperty("isstacked") && IsOpticalMediaFile())
1009 CStdString strLabel = GetLabel();
1010 CStdString strTitle, strTitleAndYear, strYear;
1011 CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, (bIsFolder || !g_guiSettings.GetBool("filelists.showextensions") ) );
1012 SetLabel(strTitleAndYear);
1015 void CFileItem::SetLabel(const CStdString &strLabel)
1019 m_bIsParentFolder=true;
1021 m_specialSort = SORT_ON_TOP;
1022 SetLabelPreformated(true);
1024 CGUIListItem::SetLabel(strLabel);
1027 void CFileItem::SetFileSizeLabel()
1029 if( m_bIsFolder && m_dwSize == 0 )
1032 SetLabel2(StringUtils::SizeToString(m_dwSize));
1035 CURL CFileItem::GetAsUrl() const
1037 return CURL(m_strPath);
1040 bool CFileItem::CanQueue() const
1045 void CFileItem::SetCanQueue(bool bYesNo)
1050 bool CFileItem::IsParentFolder() const
1052 return m_bIsParentFolder;
1055 const CStdString& CFileItem::GetMimeType(bool lookup /*= true*/) const
1057 if( m_mimetype.IsEmpty() && lookup)
1059 // discard const qualifyier
1060 CStdString& m_ref = (CStdString&)m_mimetype;
1063 m_ref = "x-directory/normal";
1064 else if( m_strPath.Left(8).Equals("shout://")
1065 || m_strPath.Left(7).Equals("http://")
1066 || m_strPath.Left(8).Equals("https://"))
1068 CFileCurl::GetMimeType(GetAsUrl(), m_ref);
1070 // try to get mime-type again but with an NSPlayer User-Agent
1071 // in order for server to provide correct mime-type. Allows us
1072 // to properly detect an MMS stream
1073 if (m_ref.Left(11).Equals("video/x-ms-"))
1074 CFileCurl::GetMimeType(GetAsUrl(), m_ref, "NSPlayer/11.00.6001.7000");
1076 // make sure there are no options set in mime-type
1077 // mime-type can look like "video/x-ms-asf ; charset=utf8"
1078 int i = m_ref.Find(';');
1080 m_ref.Delete(i,m_ref.length()-i);
1084 // if it's still empty set to an unknown type
1085 if( m_ref.IsEmpty() )
1086 m_ref = "application/octet-stream";
1089 // change protocol to mms for the following mome-type. Allows us to create proper FileMMS.
1090 if( m_mimetype.Left(32).Equals("application/vnd.ms.wms-hdr.asfv1") || m_mimetype.Left(24).Equals("application/x-mms-framed") )
1092 CStdString& m_path = (CStdString&)m_strPath;
1093 m_path.Replace("http:", "mms:");
1099 bool CFileItem::IsSamePath(const CFileItem *item) const
1104 if (item->m_strPath == m_strPath && item->m_lStartOffset == m_lStartOffset) return true;
1105 if (IsMusicDb() && HasMusicInfoTag())
1107 CFileItem dbItem(m_musicInfoTag->GetURL(), false);
1108 dbItem.m_lStartOffset = m_lStartOffset;
1109 return dbItem.IsSamePath(item);
1111 if (IsVideoDb() && HasVideoInfoTag())
1113 CFileItem dbItem(m_videoInfoTag->m_strFileNameAndPath, false);
1114 dbItem.m_lStartOffset = m_lStartOffset;
1115 return dbItem.IsSamePath(item);
1117 if (item->IsMusicDb() && item->HasMusicInfoTag())
1119 CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
1120 dbItem.m_lStartOffset = item->m_lStartOffset;
1121 return IsSamePath(&dbItem);
1123 if (item->IsVideoDb() && item->HasVideoInfoTag())
1125 CFileItem dbItem(item->m_videoInfoTag->m_strFileNameAndPath, false);
1126 dbItem.m_lStartOffset = item->m_lStartOffset;
1127 return IsSamePath(&dbItem);
1129 if (HasProperty("original_listitem_url"))
1130 return (GetProperty("original_listitem_url") == item->m_strPath);
1134 bool CFileItem::IsAlbum() const
1139 void CFileItem::UpdateInfo(const CFileItem &item)
1141 if (item.HasVideoInfoTag())
1142 { // copy info across (TODO: premiered info is normally stored in m_dateTime by the db)
1143 *GetVideoInfoTag() = *item.GetVideoInfoTag();
1144 SetOverlayImage(ICON_OVERLAY_UNWATCHED, GetVideoInfoTag()->m_playCount > 0);
1146 if (item.HasMusicInfoTag())
1147 *GetMusicInfoTag() = *item.GetMusicInfoTag();
1148 if (item.HasPictureInfoTag())
1149 *GetPictureInfoTag() = *item.GetPictureInfoTag();
1151 if (!item.GetLabel().IsEmpty())
1152 SetLabel(item.GetLabel());
1153 if (!item.GetLabel2().IsEmpty())
1154 SetLabel2(item.GetLabel2());
1155 if (!item.GetThumbnailImage().IsEmpty())
1156 SetThumbnailImage(item.GetThumbnailImage());
1157 if (!item.GetIconImage().IsEmpty())
1158 SetIconImage(item.GetIconImage());
1159 AppendProperties(item);
1162 /////////////////////////////////////////////////////////////////////////////////
1166 //////////////////////////////////////////////////////////////////////////////////
1168 CFileItemList::CFileItemList()
1170 m_fastLookup = false;
1172 m_cacheToDisc=CACHE_IF_SLOW;
1173 m_sortMethod=SORT_METHOD_NONE;
1174 m_sortOrder=SORT_ORDER_NONE;
1175 m_sortIgnoreFolders = false;
1176 m_replaceListing = false;
1179 CFileItemList::CFileItemList(const CStdString& strPath)
1182 m_fastLookup = false;
1184 m_cacheToDisc=CACHE_IF_SLOW;
1185 m_sortMethod=SORT_METHOD_NONE;
1186 m_sortOrder=SORT_ORDER_NONE;
1187 m_sortIgnoreFolders = false;
1188 m_replaceListing = false;
1191 CFileItemList::~CFileItemList()
1196 CFileItemPtr CFileItemList::operator[] (int iItem)
1201 const CFileItemPtr CFileItemList::operator[] (int iItem) const
1206 CFileItemPtr CFileItemList::operator[] (const CStdString& strPath)
1208 return Get(strPath);
1211 const CFileItemPtr CFileItemList::operator[] (const CStdString& strPath) const
1213 return Get(strPath);
1216 void CFileItemList::SetFastLookup(bool fastLookup)
1218 CSingleLock lock(m_lock);
1220 if (fastLookup && !m_fastLookup)
1221 { // generate the map
1223 for (unsigned int i=0; i < m_items.size(); i++)
1225 CFileItemPtr pItem = m_items[i];
1226 CStdString path(pItem->m_strPath); path.ToLower();
1227 m_map.insert(MAPFILEITEMSPAIR(path, pItem));
1230 if (!fastLookup && m_fastLookup)
1232 m_fastLookup = fastLookup;
1235 bool CFileItemList::Contains(const CStdString& fileName) const
1237 CSingleLock lock(m_lock);
1239 // checks case insensitive
1240 CStdString checkPath(fileName); checkPath.ToLower();
1242 return m_map.find(checkPath) != m_map.end();
1244 for (unsigned int i = 0; i < m_items.size(); i++)
1246 const CFileItemPtr pItem = m_items[i];
1247 if (pItem->m_strPath.Equals(checkPath))
1253 void CFileItemList::Clear()
1255 CSingleLock lock(m_lock);
1258 m_sortMethod=SORT_METHOD_NONE;
1259 m_sortOrder=SORT_ORDER_NONE;
1260 m_sortIgnoreFolders = false;
1261 m_cacheToDisc=CACHE_IF_SLOW;
1262 m_sortDetails.clear();
1263 m_replaceListing = false;
1267 void CFileItemList::ClearItems()
1269 CSingleLock lock(m_lock);
1270 // make sure we free the memory of the items (these are GUIControls which may have allocated resources)
1272 for (unsigned int i = 0; i < m_items.size(); i++)
1274 CFileItemPtr item = m_items[i];
1281 void CFileItemList::Add(const CFileItemPtr &pItem)
1283 CSingleLock lock(m_lock);
1285 m_items.push_back(pItem);
1288 CStdString path(pItem->m_strPath);
1290 m_map.insert(MAPFILEITEMSPAIR(path, pItem));
1294 void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition)
1296 CSingleLock lock(m_lock);
1298 if (itemPosition >= 0)
1300 m_items.insert(m_items.begin()+itemPosition, pItem);
1304 m_items.insert(m_items.begin()+(m_items.size()+itemPosition), pItem);
1308 CStdString path(pItem->m_strPath); path.ToLower();
1309 m_map.insert(MAPFILEITEMSPAIR(path, pItem));
1313 void CFileItemList::Remove(CFileItem* pItem)
1315 CSingleLock lock(m_lock);
1317 for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it)
1319 if (pItem == it->get())
1324 CStdString path(pItem->m_strPath); path.ToLower();
1332 void CFileItemList::Remove(int iItem)
1334 CSingleLock lock(m_lock);
1336 if (iItem >= 0 && iItem < (int)Size())
1338 CFileItemPtr pItem = *(m_items.begin() + iItem);
1341 CStdString path(pItem->m_strPath); path.ToLower();
1344 m_items.erase(m_items.begin() + iItem);
1348 void CFileItemList::Append(const CFileItemList& itemlist)
1350 CSingleLock lock(m_lock);
1352 for (int i = 0; i < itemlist.Size(); ++i)
1356 void CFileItemList::Assign(const CFileItemList& itemlist, bool append)
1358 CSingleLock lock(m_lock);
1362 m_strPath = itemlist.m_strPath;
1363 m_sortDetails = itemlist.m_sortDetails;
1364 m_replaceListing = itemlist.m_replaceListing;
1365 m_content = itemlist.m_content;
1366 m_mapProperties = itemlist.m_mapProperties;
1367 m_cacheToDisc = itemlist.m_cacheToDisc;
1370 bool CFileItemList::Copy(const CFileItemList& items)
1372 // assign all CFileItem parts
1373 *(CFileItem*)this = *(CFileItem*)&items;
1375 // assign the rest of the CFileItemList properties
1376 m_replaceListing = items.m_replaceListing;
1377 m_content = items.m_content;
1378 m_mapProperties = items.m_mapProperties;
1379 m_cacheToDisc = items.m_cacheToDisc;
1380 m_sortDetails = items.m_sortDetails;
1381 m_sortMethod = items.m_sortMethod;
1382 m_sortOrder = items.m_sortOrder;
1383 m_sortIgnoreFolders = items.m_sortIgnoreFolders;
1385 // make a copy of each item
1386 for (int i = 0; i < items.Size(); i++)
1388 CFileItemPtr newItem(new CFileItem(*items[i]));
1395 CFileItemPtr CFileItemList::Get(int iItem)
1397 CSingleLock lock(m_lock);
1399 if (iItem > -1 && iItem < (int)m_items.size())
1400 return m_items[iItem];
1402 return CFileItemPtr();
1405 const CFileItemPtr CFileItemList::Get(int iItem) const
1407 CSingleLock lock(m_lock);
1409 if (iItem > -1 && iItem < (int)m_items.size())
1410 return m_items[iItem];
1412 return CFileItemPtr();
1415 CFileItemPtr CFileItemList::Get(const CStdString& strPath)
1417 CSingleLock lock(m_lock);
1419 CStdString pathToCheck(strPath); pathToCheck.ToLower();
1422 IMAPFILEITEMS it=m_map.find(pathToCheck);
1423 if (it != m_map.end())
1426 return CFileItemPtr();
1429 for (unsigned int i = 0; i < m_items.size(); i++)
1431 CFileItemPtr pItem = m_items[i];
1432 if (pItem->m_strPath.Equals(pathToCheck))
1436 return CFileItemPtr();
1439 const CFileItemPtr CFileItemList::Get(const CStdString& strPath) const
1441 CSingleLock lock(m_lock);
1443 CStdString pathToCheck(strPath); pathToCheck.ToLower();
1446 map<CStdString, CFileItemPtr>::const_iterator it=m_map.find(pathToCheck);
1447 if (it != m_map.end())
1450 return CFileItemPtr();
1453 for (unsigned int i = 0; i < m_items.size(); i++)
1455 CFileItemPtr pItem = m_items[i];
1456 if (pItem->m_strPath.Equals(pathToCheck))
1460 return CFileItemPtr();
1463 int CFileItemList::Size() const
1465 CSingleLock lock(m_lock);
1466 return (int)m_items.size();
1469 bool CFileItemList::IsEmpty() const
1471 CSingleLock lock(m_lock);
1472 return (m_items.size() <= 0);
1475 void CFileItemList::Reserve(int iCount)
1477 CSingleLock lock(m_lock);
1478 m_items.reserve(iCount);
1481 void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func)
1483 CSingleLock lock(m_lock);
1484 std::stable_sort(m_items.begin(), m_items.end(), func);
1487 void CFileItemList::FillSortFields(FILEITEMFILLFUNC func)
1489 CSingleLock lock(m_lock);
1490 std::for_each(m_items.begin(), m_items.end(), func);
1493 void CFileItemList::Sort(SORT_METHOD sortMethod, SORT_ORDER sortOrder)
1496 if (sortMethod==m_sortMethod && m_sortOrder==sortOrder)
1501 case SORT_METHOD_LABEL:
1502 case SORT_METHOD_LABEL_IGNORE_FOLDERS:
1503 FillSortFields(SSortFileItem::ByLabel);
1505 case SORT_METHOD_LABEL_IGNORE_THE:
1506 FillSortFields(SSortFileItem::ByLabelNoThe);
1508 case SORT_METHOD_DATE:
1509 FillSortFields(SSortFileItem::ByDate);
1511 case SORT_METHOD_SIZE:
1512 FillSortFields(SSortFileItem::BySize);
1514 case SORT_METHOD_BITRATE:
1515 FillSortFields(SSortFileItem::ByBitrate);
1517 case SORT_METHOD_DRIVE_TYPE:
1518 FillSortFields(SSortFileItem::ByDriveType);
1520 case SORT_METHOD_TRACKNUM:
1521 FillSortFields(SSortFileItem::BySongTrackNum);
1523 case SORT_METHOD_EPISODE:
1524 FillSortFields(SSortFileItem::ByEpisodeNum);
1526 case SORT_METHOD_DURATION:
1527 FillSortFields(SSortFileItem::BySongDuration);
1529 case SORT_METHOD_TITLE_IGNORE_THE:
1530 FillSortFields(SSortFileItem::BySongTitleNoThe);
1532 case SORT_METHOD_TITLE:
1533 FillSortFields(SSortFileItem::BySongTitle);
1535 case SORT_METHOD_ARTIST:
1536 FillSortFields(SSortFileItem::BySongArtist);
1538 case SORT_METHOD_ARTIST_IGNORE_THE:
1539 FillSortFields(SSortFileItem::BySongArtistNoThe);
1541 case SORT_METHOD_ALBUM:
1542 FillSortFields(SSortFileItem::BySongAlbum);
1544 case SORT_METHOD_ALBUM_IGNORE_THE:
1545 FillSortFields(SSortFileItem::BySongAlbumNoThe);
1547 case SORT_METHOD_GENRE:
1548 FillSortFields(SSortFileItem::ByGenre);
1550 case SORT_METHOD_COUNTRY:
1551 FillSortFields(SSortFileItem::ByCountry);
1553 case SORT_METHOD_DATEADDED:
1554 FillSortFields(SSortFileItem::ByDateAdded);
1556 case SORT_METHOD_FILE:
1557 FillSortFields(SSortFileItem::ByFile);
1559 case SORT_METHOD_VIDEO_RATING:
1560 FillSortFields(SSortFileItem::ByMovieRating);
1562 case SORT_METHOD_VIDEO_TITLE:
1563 FillSortFields(SSortFileItem::ByMovieTitle);
1565 case SORT_METHOD_VIDEO_SORT_TITLE:
1566 FillSortFields(SSortFileItem::ByMovieSortTitle);
1568 case SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE:
1569 FillSortFields(SSortFileItem::ByMovieSortTitleNoThe);
1571 case SORT_METHOD_YEAR:
1572 FillSortFields(SSortFileItem::ByYear);
1574 case SORT_METHOD_PRODUCTIONCODE:
1575 FillSortFields(SSortFileItem::ByProductionCode);
1577 case SORT_METHOD_PROGRAM_COUNT:
1578 case SORT_METHOD_PLAYLIST_ORDER:
1579 // TODO: Playlist order is hacked into program count variable (not nice, but ok until 2.0)
1580 FillSortFields(SSortFileItem::ByProgramCount);
1582 case SORT_METHOD_SONG_RATING:
1583 FillSortFields(SSortFileItem::BySongRating);
1585 case SORT_METHOD_MPAA_RATING:
1586 FillSortFields(SSortFileItem::ByMPAARating);
1588 case SORT_METHOD_VIDEO_RUNTIME:
1589 FillSortFields(SSortFileItem::ByMovieRuntime);
1591 case SORT_METHOD_STUDIO:
1592 FillSortFields(SSortFileItem::ByStudio);
1594 case SORT_METHOD_STUDIO_IGNORE_THE:
1595 FillSortFields(SSortFileItem::ByStudioNoThe);
1597 case SORT_METHOD_FULLPATH:
1598 FillSortFields(SSortFileItem::ByFullPath);
1600 case SORT_METHOD_LASTPLAYED:
1601 FillSortFields(SSortFileItem::ByLastPlayed);
1603 case SORT_METHOD_PLAYCOUNT:
1604 FillSortFields(SSortFileItem::ByPlayCount);
1606 case SORT_METHOD_LISTENERS:
1607 FillSortFields(SSortFileItem::ByListeners);
1612 if (sortMethod == SORT_METHOD_FILE ||
1613 sortMethod == SORT_METHOD_VIDEO_SORT_TITLE ||
1614 sortMethod == SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE ||
1615 sortMethod == SORT_METHOD_LABEL_IGNORE_FOLDERS ||
1616 m_sortIgnoreFolders)
1617 Sort(sortOrder==SORT_ORDER_ASC ? SSortFileItem::IgnoreFoldersAscending : SSortFileItem::IgnoreFoldersDescending);
1618 else if (sortMethod != SORT_METHOD_NONE && sortMethod != SORT_METHOD_UNSORTED)
1619 Sort(sortOrder==SORT_ORDER_ASC ? SSortFileItem::Ascending : SSortFileItem::Descending);
1621 m_sortMethod=sortMethod;
1622 m_sortOrder=sortOrder;
1625 void CFileItemList::Randomize()
1627 CSingleLock lock(m_lock);
1628 random_shuffle(m_items.begin(), m_items.end());
1631 void CFileItemList::Archive(CArchive& ar)
1633 CSingleLock lock(m_lock);
1636 CFileItem::Archive(ar);
1639 if (m_items.size() > 0 && m_items[0]->IsParentFolder())
1642 ar << (int)(m_items.size() - i);
1646 ar << (int)m_sortMethod;
1647 ar << (int)m_sortOrder;
1648 ar << m_sortIgnoreFolders;
1649 ar << (int)m_cacheToDisc;
1651 ar << (int)m_sortDetails.size();
1652 for (unsigned int j = 0; j < m_sortDetails.size(); ++j)
1654 const SORT_METHOD_DETAILS &details = m_sortDetails[j];
1655 ar << (int)details.m_sortMethod;
1656 ar << details.m_buttonLabel;
1657 ar << details.m_labelMasks.m_strLabelFile;
1658 ar << details.m_labelMasks.m_strLabelFolder;
1659 ar << details.m_labelMasks.m_strLabel2File;
1660 ar << details.m_labelMasks.m_strLabel2Folder;
1665 for (; i < (int)m_items.size(); ++i)
1667 CFileItemPtr pItem = m_items[i];
1673 CFileItemPtr pParent;
1676 CFileItemPtr pItem=m_items[0];
1677 if (pItem->IsParentFolder())
1678 pParent.reset(new CFileItem(*pItem));
1681 SetFastLookup(false);
1685 CFileItem::Archive(ar);
1694 m_items.reserve(iSize + 1);
1695 m_items.push_back(pParent);
1698 m_items.reserve(iSize);
1700 bool fastLookup=false;
1704 ar >> (int&)tempint;
1705 m_sortMethod = SORT_METHOD(tempint);
1706 ar >> (int&)tempint;
1707 m_sortOrder = SORT_ORDER(tempint);
1708 ar >> m_sortIgnoreFolders;
1709 ar >> (int&)tempint;
1710 m_cacheToDisc = CACHE_TYPE(tempint);
1712 unsigned int detailSize = 0;
1714 for (unsigned int j = 0; j < detailSize; ++j)
1716 SORT_METHOD_DETAILS details;
1717 ar >> (int&)tempint;
1718 details.m_sortMethod = SORT_METHOD(tempint);
1719 ar >> details.m_buttonLabel;
1720 ar >> details.m_labelMasks.m_strLabelFile;
1721 ar >> details.m_labelMasks.m_strLabelFolder;
1722 ar >> details.m_labelMasks.m_strLabel2File;
1723 ar >> details.m_labelMasks.m_strLabel2Folder;
1724 m_sortDetails.push_back(details);
1729 for (int i = 0; i < iSize; ++i)
1731 CFileItemPtr pItem(new CFileItem);
1736 SetFastLookup(fastLookup);
1740 void CFileItemList::FillInDefaultIcons()
1742 CSingleLock lock(m_lock);
1743 for (int i = 0; i < (int)m_items.size(); ++i)
1745 CFileItemPtr pItem = m_items[i];
1746 pItem->FillInDefaultIcon();
1750 void CFileItemList::SetMusicThumbs()
1752 CSingleLock lock(m_lock);
1753 //cache thumbnails directory
1754 g_directoryCache.InitMusicThumbCache();
1756 for (int i = 0; i < (int)m_items.size(); ++i)
1758 CFileItemPtr pItem = m_items[i];
1759 pItem->SetMusicThumb();
1762 g_directoryCache.ClearMusicThumbCache();
1765 int CFileItemList::GetFolderCount() const
1767 CSingleLock lock(m_lock);
1768 int nFolderCount = 0;
1769 for (int i = 0; i < (int)m_items.size(); i++)
1771 CFileItemPtr pItem = m_items[i];
1772 if (pItem->m_bIsFolder)
1776 return nFolderCount;
1779 int CFileItemList::GetObjectCount() const
1781 CSingleLock lock(m_lock);
1783 int numObjects = (int)m_items.size();
1784 if (numObjects && m_items[0]->IsParentFolder())
1790 int CFileItemList::GetFileCount() const
1792 CSingleLock lock(m_lock);
1794 for (int i = 0; i < (int)m_items.size(); i++)
1796 CFileItemPtr pItem = m_items[i];
1797 if (!pItem->m_bIsFolder)
1804 int CFileItemList::GetSelectedCount() const
1806 CSingleLock lock(m_lock);
1808 for (int i = 0; i < (int)m_items.size(); i++)
1810 CFileItemPtr pItem = m_items[i];
1811 if (pItem->IsSelected())
1818 void CFileItemList::FilterCueItems()
1820 CSingleLock lock(m_lock);
1821 // Handle .CUE sheet files...
1822 VECSONGS itemstoadd;
1823 CStdStringArray itemstodelete;
1824 for (int i = 0; i < (int)m_items.size(); i++)
1826 CFileItemPtr pItem = m_items[i];
1827 if (!pItem->m_bIsFolder)
1828 { // see if it's a .CUE sheet
1829 if (pItem->IsCUESheet())
1831 CCueDocument cuesheet;
1832 if (cuesheet.Parse(pItem->m_strPath))
1835 cuesheet.GetSongs(newitems);
1837 std::vector<CStdString> MediaFileVec;
1838 cuesheet.GetMediaFiles(MediaFileVec);
1840 // queue the cue sheet and the underlying media file for deletion
1841 for(std::vector<CStdString>::iterator itMedia = MediaFileVec.begin(); itMedia != MediaFileVec.end(); itMedia++)
1843 CStdString strMediaFile = *itMedia;
1844 CStdString fileFromCue = strMediaFile; // save the file from the cue we're matching against,
1845 // as we're going to search for others here...
1846 bool bFoundMediaFile = CFile::Exists(strMediaFile);
1847 // queue the cue sheet and the underlying media file for deletion
1848 if (!bFoundMediaFile)
1850 // try file in same dir, not matching case...
1851 if (Contains(strMediaFile))
1853 bFoundMediaFile = true;
1857 // try removing the .cue extension...
1858 strMediaFile = pItem->m_strPath;
1859 URIUtils::RemoveExtension(strMediaFile);
1860 CFileItem item(strMediaFile, false);
1861 if (item.IsAudio() && Contains(strMediaFile))
1863 bFoundMediaFile = true;
1866 { // try replacing the extension with one of our allowed ones.
1867 CStdStringArray extensions;
1868 StringUtils::SplitString(g_settings.m_musicExtensions, "|", extensions);
1869 for (unsigned int i = 0; i < extensions.size(); i++)
1871 strMediaFile = URIUtils::ReplaceExtension(pItem->m_strPath, extensions[i]);
1872 CFileItem item(strMediaFile, false);
1873 if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile))
1875 bFoundMediaFile = true;
1882 if (bFoundMediaFile)
1884 itemstodelete.push_back(pItem->m_strPath);
1885 itemstodelete.push_back(strMediaFile);
1886 // get the additional stuff (year, genre etc.) from the underlying media files tag.
1888 auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(strMediaFile));
1889 if (NULL != pLoader.get())
1892 pLoader->Load(strMediaFile, tag);
1894 // fill in any missing entries from underlying media file
1895 for (int j = 0; j < (int)newitems.size(); j++)
1897 CSong song = newitems[j];
1898 // only for songs that actually match the current media file
1899 if (song.strFileName == fileFromCue)
1901 // we might have a new media file from the above matching code
1902 song.strFileName = strMediaFile;
1905 if (song.strAlbum.empty() && !tag.GetAlbum().empty()) song.strAlbum = tag.GetAlbum();
1906 if (song.strAlbumArtist.empty() && !tag.GetAlbumArtist().empty()) song.strAlbumArtist = tag.GetAlbumArtist();
1907 if (song.strGenre.empty() && !tag.GetGenre().empty()) song.strGenre = tag.GetGenre();
1908 if (song.strArtist.empty() && !tag.GetArtist().empty()) song.strArtist = tag.GetArtist();
1909 if (tag.GetDiscNumber()) song.iTrack |= (tag.GetDiscNumber() << 16); // see CMusicInfoTag::GetDiscNumber()
1910 SYSTEMTIME dateTime;
1911 tag.GetReleaseDate(dateTime);
1912 if (dateTime.wYear) song.iYear = dateTime.wYear;
1914 if (!song.iDuration && tag.GetDuration() > 0)
1915 { // must be the last song
1916 song.iDuration = (tag.GetDuration() * 75 - song.iStartOffset + 37) / 75;
1918 // add this item to the list
1919 itemstoadd.push_back(song);
1924 { // remove the .cue sheet from the directory
1925 itemstodelete.push_back(pItem->m_strPath);
1930 { // remove the .cue sheet from the directory (can't parse it - no point listing it)
1931 itemstodelete.push_back(pItem->m_strPath);
1936 // now delete the .CUE files and underlying media files.
1937 for (int i = 0; i < (int)itemstodelete.size(); i++)
1939 for (int j = 0; j < (int)m_items.size(); j++)
1941 CFileItemPtr pItem = m_items[j];
1942 if (stricmp(pItem->m_strPath.c_str(), itemstodelete[i].c_str()) == 0)
1943 { // delete this item
1944 m_items.erase(m_items.begin() + j);
1949 // and add the files from the .CUE sheet
1950 for (int i = 0; i < (int)itemstoadd.size(); i++)
1952 // now create the file item, and add to the item list.
1953 CFileItemPtr pItem(new CFileItem(itemstoadd[i]));
1954 m_items.push_back(pItem);
1958 // Remove the extensions from the filenames
1959 void CFileItemList::RemoveExtensions()
1961 CSingleLock lock(m_lock);
1962 for (int i = 0; i < Size(); ++i)
1963 m_items[i]->RemoveExtension();
1966 void CFileItemList::Stack()
1968 CSingleLock lock(m_lock);
1971 if (IsVirtualDirectoryRoot() || IsLiveTV() || m_strPath.Left(10).Equals("sources://"))
1974 SetProperty("isstacked", "1");
1976 // items needs to be sorted for stuff below to work properly
1977 Sort(SORT_METHOD_LABEL, SORT_ORDER_ASC);
1981 for (i = 0; i < Size(); ++i)
1983 CFileItemPtr item = Get(i);
1984 // combined the folder checks
1985 if (item->m_bIsFolder)
1987 // only check known fast sources?
1989 // 1. rars and zips may be on slow sources? is this supposed to be allowed?
1990 if( !item->IsRemote()
1992 || URIUtils::IsInRAR(item->m_strPath)
1993 || URIUtils::IsInZIP(item->m_strPath)
1996 // stack cd# folders if contains only a single video file
1997 // NOTE: if we're doing this anyway, why not collapse *all* folders with just a single video file?
1998 CStdString folderName = item->GetLabel();
1999 if (folderName.Left(2).Equals("CD") && StringUtils::IsNaturalNumber(folderName.Mid(2)))
2001 CFileItemList items;
2002 CDirectory::GetDirectory(item->m_strPath,items,g_settings.m_videoExtensions,true);
2003 // optimized to only traverse listing once by checking for filecount
2004 // and recording last file item for later use
2007 for (int j = 0; j < items.Size(); j++)
2009 if (!items[j]->m_bIsFolder)
2019 *item = *items[index];
2023 // check for dvd folders
2028 URIUtils::AddFileToFolder(item->m_strPath, "VIDEO_TS.IFO", path);
2029 if (CFile::Exists(path))
2033 URIUtils::AddFileToFolder(item->m_strPath, "VIDEO_TS", dvdPath);
2034 URIUtils::AddFileToFolder(dvdPath, "VIDEO_TS.IFO", path);
2036 if (CFile::Exists(path))
2039 #ifdef HAVE_LIBBLURAY
2040 if (dvdPath.IsEmpty())
2042 URIUtils::AddFileToFolder(item->m_strPath, "index.bdmv", path);
2043 if (CFile::Exists(path))
2047 URIUtils::AddFileToFolder(item->m_strPath, "BDMV", dvdPath);
2048 URIUtils::AddFileToFolder(dvdPath, "index.bdmv", path);
2050 if (CFile::Exists(path))
2055 if (!dvdPath.IsEmpty())
2057 // NOTE: should this be done for the CD# folders too?
2058 /* set the thumbnail based on folder */
2059 item->SetCachedVideoThumb();
2060 if (!item->HasThumbnail())
2061 item->SetUserVideoThumb();
2063 item->m_bIsFolder = false;
2064 item->m_strPath = dvdPath;
2065 item->SetLabel2("");
2066 item->SetLabelPreformated(true);
2067 m_sortMethod = SORT_METHOD_NONE; /* sorting is now broken */
2069 /* override the previously set thumb if video_ts.ifo has any */
2070 /* otherwise user can't set icon on the stacked file as that */
2071 /* will allways be set on the video_ts.ifo file */
2072 CStdString thumb(item->GetCachedVideoThumb());
2073 if(CFile::Exists(thumb))
2074 item->SetThumbnailImage(thumb);
2076 item->SetUserVideoThumb();
2083 // Precompile our REs
2084 VECCREGEXP stackRegExps;
2085 CRegExp tmpRegExp(true);
2086 const CStdStringArray& strStackRegExps = g_advancedSettings.m_videoStackRegExps;
2087 CStdStringArray::const_iterator strRegExp = strStackRegExps.begin();
2088 while (strRegExp != strStackRegExps.end())
2090 if (tmpRegExp.RegComp(*strRegExp))
2092 if (tmpRegExp.GetCaptureTotal() == 4)
2093 stackRegExps.push_back(tmpRegExp);
2095 CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have 4 captures.", strRegExp->c_str());
2100 // now stack the files, some of which may be from the previous stack iteration
2104 CFileItemPtr item1 = Get(i);
2107 item1->SetProperty("isstacked", "1");
2109 // skip folders, nfo files, playlists
2110 if (item1->m_bIsFolder
2111 || item1->IsParentFolder()
2113 || item1->IsPlayList()
2123 CStdString stackName;
2125 CStdString filePath;
2127 VECCREGEXP::iterator expr = stackRegExps.begin();
2129 URIUtils::Split(item1->m_strPath, filePath, file1);
2131 while (expr != stackRegExps.end())
2133 if (expr->RegFind(file1, offset) != -1)
2135 CStdString Title1 = expr->GetMatch(1),
2136 Volume1 = expr->GetMatch(2),
2137 Ignore1 = expr->GetMatch(3),
2138 Extension1 = expr->GetMatch(4);
2140 Title1 = file1.substr(0, expr->GetSubStart(2));
2144 CFileItemPtr item2 = Get(j);
2146 // skip folders, nfo files, playlists
2147 if (item2->m_bIsFolder
2148 || item2->IsParentFolder()
2150 || item2->IsPlayList()
2158 CStdString file2, filePath2;
2159 URIUtils::Split(item2->m_strPath, filePath2, file2);
2161 if (expr->RegFind(file2, offset) != -1)
2163 CStdString Title2 = expr->GetMatch(1),
2164 Volume2 = expr->GetMatch(2),
2165 Ignore2 = expr->GetMatch(3),
2166 Extension2 = expr->GetMatch(4);
2168 Title2 = file2.substr(0, expr->GetSubStart(2));
2169 if (Title1.Equals(Title2))
2171 if (!Volume1.Equals(Volume2))
2173 if (Ignore1.Equals(Ignore2) && Extension1.Equals(Extension2))
2175 if (stack.size() == 0)
2177 stackName = Title1 + Ignore1 + Extension1;
2179 size += item1->m_dwSize;
2182 size += item2->m_dwSize;
2191 else if (!Ignore1.Equals(Ignore2)) // False positive, try again with offset
2193 offset = expr->GetSubStart(3);
2196 else // Extension mismatch
2203 else // Title mismatch
2210 else // No match 2, next expression
2219 expr = stackRegExps.end();
2226 if (stack.size() > 1)
2228 // have a stack, remove the items and add the stacked item
2229 // dont actually stack a multipart rar set, just remove all items but the first
2230 CStdString stackPath;
2231 if (Get(stack[0])->IsRAR())
2232 stackPath = Get(stack[0])->m_strPath;
2235 CStackDirectory dir;
2236 stackPath = dir.ConstructStackPath(*this, stack);
2238 item1->m_strPath = stackPath;
2240 for (unsigned k = 1; k < stack.size(); k++)
2242 // item->m_bIsFolder = true; // don't treat stacked files as folders
2243 // the label may be in a different char set from the filename (eg over smb
2244 // the label is converted from utf8, but the filename is not)
2245 if (!g_guiSettings.GetBool("filelists.showextensions"))
2246 URIUtils::RemoveExtension(stackName);
2247 CURL::Decode(stackName);
2248 item1->SetLabel(stackName);
2249 item1->m_dwSize = size;
2257 bool CFileItemList::Load(int windowID)
2260 if (file.Open(GetDiscCacheFile(windowID)))
2262 CLog::Log(LOGDEBUG,"Loading fileitems [%s]",m_strPath.c_str());
2263 CArchive ar(&file, CArchive::load);
2265 CLog::Log(LOGDEBUG," -- items: %i, directory: %s sort method: %i, ascending: %s",Size(),m_strPath.c_str(), m_sortMethod, m_sortOrder ? "true" : "false");
2274 bool CFileItemList::Save(int windowID)
2280 CLog::Log(LOGDEBUG,"Saving fileitems [%s]",m_strPath.c_str());
2283 if (file.OpenForWrite(GetDiscCacheFile(windowID), true)) // overwrite always
2285 CArchive ar(&file, CArchive::store);
2287 CLog::Log(LOGDEBUG," -- items: %i, sort method: %i, ascending: %s",iSize,m_sortMethod, m_sortOrder ? "true" : "false");
2296 void CFileItemList::RemoveDiscCache(int windowID) const
2298 CStdString cacheFile(GetDiscCacheFile(windowID));
2299 if (CFile::Exists(cacheFile))
2301 CLog::Log(LOGDEBUG,"Clearing cached fileitems [%s]",m_strPath.c_str());
2302 CFile::Delete(cacheFile);
2306 CStdString CFileItemList::GetDiscCacheFile(int windowID) const
2308 CStdString strPath=m_strPath;
2309 URIUtils::RemoveSlashAtEnd(strPath);
2312 crc.ComputeFromLowerCase(strPath);
2314 CStdString cacheFile;
2315 if (IsCDDA() || IsOnDVD())
2316 cacheFile.Format("special://temp/r-%08x.fi", (unsigned __int32)crc);
2317 else if (IsMusicDb())
2318 cacheFile.Format("special://temp/mdb-%08x.fi", (unsigned __int32)crc);
2319 else if (IsVideoDb())
2320 cacheFile.Format("special://temp/vdb-%08x.fi", (unsigned __int32)crc);
2322 cacheFile.Format("special://temp/%i-%08x.fi", windowID, (unsigned __int32)crc);
2324 cacheFile.Format("special://temp/%08x.fi", (unsigned __int32)crc);
2328 bool CFileItemList::AlwaysCache() const
2330 // some database folders are always cached
2332 return CMusicDatabaseDirectory::CanCache(m_strPath);
2334 return CVideoDatabaseDirectory::CanCache(m_strPath);
2338 void CFileItemList::SetCachedVideoThumbs()
2340 CSingleLock lock(m_lock);
2341 // TODO: Investigate caching time to see if it speeds things up
2342 for (unsigned int i = 0; i < m_items.size(); ++i)
2344 CFileItemPtr pItem = m_items[i];
2345 pItem->SetCachedVideoThumb();
2349 void CFileItemList::SetCachedMusicThumbs()
2351 CSingleLock lock(m_lock);
2352 // TODO: Investigate caching time to see if it speeds things up
2353 for (unsigned int i = 0; i < m_items.size(); ++i)
2355 CFileItemPtr pItem = m_items[i];
2356 pItem->SetCachedMusicThumb();
2360 void CFileItem::SetCachedMusicThumb()
2362 // if it already has a thumbnail, then return
2363 if (HasThumbnail() || m_bIsShareOrDrive) return ;
2365 // streams do not have thumbnails
2366 if (IsInternetStream()) return ;
2368 // music db items already have thumbs or there is no thumb available
2369 if (IsMusicDb()) return;
2371 // ignore the parent dir items
2372 if (IsParentFolder()) return;
2374 CStdString cachedThumb(GetPreviouslyCachedMusicThumb());
2375 if (!cachedThumb.IsEmpty())
2376 SetThumbnailImage(cachedThumb);
2377 // SetIconImage(cachedThumb);
2380 CStdString CFileItem::GetPreviouslyCachedMusicThumb() const
2382 // look if an album thumb is available,
2383 // could be any file with tags loaded or
2384 // a directory in album window
2385 CStdString strAlbum, strArtist;
2386 if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
2388 strAlbum = m_musicInfoTag->GetAlbum();
2389 if (!m_musicInfoTag->GetAlbumArtist().IsEmpty())
2390 strArtist = m_musicInfoTag->GetAlbumArtist();
2392 strArtist = m_musicInfoTag->GetArtist();
2394 if (!strAlbum.IsEmpty() && !strArtist.IsEmpty())
2396 // try permanent album thumb using "album name + artist name"
2397 CStdString thumb(CUtil::GetCachedAlbumThumb(strAlbum, strArtist));
2398 if (CFile::Exists(thumb))
2402 // if a file, try to find a cached filename.tbn
2405 // look for locally cached tbn
2406 CStdString thumb(CUtil::GetCachedMusicThumb(m_strPath));
2407 if (CFile::Exists(thumb))
2411 // try and find a cached folder thumb (folder.jpg or folder.tbn)
2414 URIUtils::GetDirectory(m_strPath, strPath);
2416 strPath = m_strPath;
2417 // music thumbs are cached without slash at end
2418 URIUtils::RemoveSlashAtEnd(strPath);
2420 CStdString thumb(CUtil::GetCachedMusicThumb(strPath));
2421 if (CFile::Exists(thumb))
2427 CStdString CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */) const
2429 if (m_strPath.IsEmpty()
2430 || m_bIsShareOrDrive
2431 || IsInternetStream()
2432 || URIUtils::IsUPnP(m_strPath)
2433 || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
2440 // we first check for <filename>.tbn or <foldername>.tbn
2441 CStdString fileThumb(GetTBNFile());
2442 if (CFile::Exists(fileThumb))
2445 // if a folder, check for folder.jpg
2446 if (m_bIsFolder && !IsFileFolder() && (!IsRemote() || alwaysCheckRemote || g_guiSettings.GetBool("musicfiles.findremotethumbs")))
2448 CStdStringArray thumbs;
2449 StringUtils::SplitString(g_advancedSettings.m_musicThumbs, "|", thumbs);
2450 for (unsigned int i = 0; i < thumbs.size(); ++i)
2452 CStdString folderThumb(GetFolderThumb(thumbs[i]));
2453 if (CFile::Exists(folderThumb))
2459 // this adds support for files which inherit a folder.jpg icon which has not been cached yet.
2460 // this occurs when queueing a top-level folder which has not been traversed yet.
2461 else if (!IsRemote() || alwaysCheckRemote || g_guiSettings.GetBool("musicfiles.findremotethumbs"))
2463 CStdString strFolder, strFile;
2464 URIUtils::Split(m_strPath, strFolder, strFile);
2465 CFileItem folderItem(strFolder, true);
2466 folderItem.SetMusicThumb(alwaysCheckRemote);
2467 if (folderItem.HasThumbnail())
2468 return folderItem.GetThumbnailImage();
2474 void CFileItem::SetUserMusicThumb(bool alwaysCheckRemote /* = false */)
2476 // caches as the local thumb
2477 CStdString thumb(GetUserMusicThumb(alwaysCheckRemote));
2478 if (!thumb.IsEmpty())
2480 CStdString cachedThumb(CUtil::GetCachedMusicThumb(m_strPath));
2481 CPicture::CreateThumbnail(thumb, cachedThumb);
2484 SetCachedMusicThumb();
2487 CStdString CFileItem::GetCachedVideoThumb() const
2490 return GetCachedThumb(CStackDirectory::GetFirstStackedFile(m_strPath),g_settings.GetVideoThumbFolder(),true);
2491 else if (IsVideoDb() && HasVideoInfoTag())
2493 if (m_bIsFolder && !GetVideoInfoTag()->m_strPath.IsEmpty())
2494 return GetCachedThumb(GetVideoInfoTag()->m_strPath, g_settings.GetVideoThumbFolder(), true);
2495 else if (!GetVideoInfoTag()->m_strFileNameAndPath.IsEmpty())
2496 return GetCachedThumb(GetVideoInfoTag()->m_strFileNameAndPath, g_settings.GetVideoThumbFolder(), true);
2498 return GetCachedThumb(m_strPath,g_settings.GetVideoThumbFolder(),true);
2501 CStdString CFileItem::GetCachedEpisodeThumb() const
2503 // get the locally cached thumb
2505 strCRC.Format("%sepisode%i",GetVideoInfoTag()->m_strFileNameAndPath.c_str(),GetVideoInfoTag()->m_iEpisode);
2506 return GetCachedThumb(strCRC,g_settings.GetVideoThumbFolder(),true);
2509 void CFileItem::SetCachedVideoThumb()
2511 if (IsParentFolder()) return;
2512 if (HasThumbnail()) return;
2513 CStdString cachedThumb(GetCachedVideoThumb());
2514 if (HasVideoInfoTag() && !m_bIsFolder &&
2515 GetVideoInfoTag()->m_iEpisode > -1 &&
2516 CFile::Exists(GetCachedEpisodeThumb()))
2518 SetThumbnailImage(GetCachedEpisodeThumb());
2520 else if (CFile::Exists(cachedThumb))
2521 SetThumbnailImage(cachedThumb);
2524 // Gets the .tbn filename from a file or folder name.
2525 // <filename>.ext -> <filename>.tbn
2526 // <foldername>/ -> <foldername>.tbn
2527 CStdString CFileItem::GetTBNFile() const
2529 CStdString thumbFile;
2530 CStdString strFile = m_strPath;
2534 CStdString strPath, strReturn;
2535 URIUtils::GetParentPath(m_strPath,strPath);
2536 CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2537 CStdString strTBNFile = item.GetTBNFile();
2538 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strReturn);
2539 if (CFile::Exists(strReturn))
2542 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)),strFile);
2545 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2547 CStdString strPath, strParent;
2548 URIUtils::GetDirectory(strFile,strPath);
2549 URIUtils::GetParentPath(strPath,strParent);
2550 URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
2554 strFile = url.GetFileName();
2556 if (m_bIsFolder && !IsFileFolder())
2557 URIUtils::RemoveSlashAtEnd(strFile);
2559 if (!strFile.IsEmpty())
2561 if (m_bIsFolder && !IsFileFolder())
2562 thumbFile = strFile + ".tbn"; // folder, so just add ".tbn"
2564 thumbFile = URIUtils::ReplaceExtension(strFile, ".tbn");
2565 url.SetFileName(thumbFile);
2566 thumbFile = url.Get();
2571 CStdString CFileItem::GetUserVideoThumb() const
2576 return g_tuxbox.GetPicon(GetLabel());
2580 if (m_strPath.IsEmpty()
2581 || m_bIsShareOrDrive
2582 || IsInternetStream()
2583 || URIUtils::IsUPnP(m_strPath)
2584 || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
2592 // 1. check <filename>.tbn or <foldername>.tbn
2593 CStdString fileThumb(GetTBNFile());
2594 if (CFile::Exists(fileThumb))
2597 // 2. - check movie.tbn, as long as it's not a folder
2600 CStdString strPath, movietbnFile;
2601 URIUtils::GetParentPath(m_strPath, strPath);
2602 URIUtils::AddFileToFolder(strPath, "movie.tbn", movietbnFile);
2603 if (CFile::Exists(movietbnFile))
2604 return movietbnFile;
2607 // 3. check folder image in_m_dvdThumbs (folder.jpg)
2608 if (m_bIsFolder && !IsFileFolder())
2610 CStdStringArray thumbs;
2611 StringUtils::SplitString(g_advancedSettings.m_dvdThumbs, "|", thumbs);
2612 for (unsigned int i = 0; i < thumbs.size(); ++i)
2614 CStdString folderThumb(GetFolderThumb(thumbs[i]));
2615 if (CFile::Exists(folderThumb))
2625 CStdString CFileItem::GetFolderThumb(const CStdString &folderJPG /* = "folder.jpg" */) const
2627 CStdString folderThumb;
2628 CStdString strFolder = m_strPath;
2631 URIUtils::IsInRAR(strFolder) ||
2632 URIUtils::IsInZIP(strFolder))
2634 URIUtils::GetParentPath(m_strPath,strFolder);
2638 strFolder = CMultiPathDirectory::GetFirstPath(m_strPath);
2640 URIUtils::AddFileToFolder(strFolder, folderJPG, folderThumb);
2644 CStdString CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const
2646 if (IsLabelPreformated())
2649 CStdString strMovieName = GetBaseMoviePath(bUseFolderNames);
2651 URIUtils::RemoveSlashAtEnd(strMovieName);
2652 strMovieName = URIUtils::GetFileName(strMovieName);
2653 CURL::Decode(strMovieName);
2655 return strMovieName;
2658 CStdString CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
2660 CStdString strMovieName = m_strPath;
2663 strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
2665 if (URIUtils::IsStack(strMovieName))
2666 strMovieName = CStackDirectory::GetStackedTitlePath(strMovieName);
2669 if ((pos=strMovieName.Find("BDMV/")) != -1 ||
2670 (pos=strMovieName.Find("BDMV\\")) != -1)
2671 strMovieName = strMovieName.Mid(0,pos+5);
2673 if ((!m_bIsFolder || IsOpticalMediaFile() || URIUtils::IsInArchive(m_strPath)) && bUseFolderNames)
2675 CStdString name2(strMovieName);
2676 URIUtils::GetParentPath(name2,strMovieName);
2677 if (URIUtils::IsInArchive(m_strPath) || strMovieName.Find( "VIDEO_TS" ) != -1)
2679 CStdString strArchivePath;
2680 URIUtils::GetParentPath(strMovieName, strArchivePath);
2681 strMovieName = strArchivePath;
2685 return strMovieName;
2688 void CFileItem::SetVideoThumb()
2690 if (HasThumbnail()) return;
2691 SetCachedVideoThumb();
2692 if (!HasThumbnail())
2693 SetUserVideoThumb();
2696 void CFileItem::SetUserVideoThumb()
2698 if (m_bIsShareOrDrive) return;
2699 if (IsParentFolder()) return;
2701 // caches as the local thumb
2702 CStdString thumb(GetUserVideoThumb());
2703 if (!thumb.IsEmpty())
2705 CStdString cachedThumb(GetCachedVideoThumb());
2706 CPicture::CreateThumbnail(thumb, cachedThumb);
2708 SetCachedVideoThumb();
2711 bool CFileItem::CacheLocalFanart() const
2713 // first check for an already cached fanart image
2714 CStdString cachedFanart(GetCachedFanart());
2715 if (CFile::Exists(cachedFanart))
2718 // we don't have a cached image, so let's see if the user has a local image, and cache it if so
2719 CStdString localFanart(GetLocalFanart());
2720 if (!localFanart.IsEmpty())
2721 return CPicture::CacheFanart(localFanart, cachedFanart);
2725 CStdString CFileItem::GetLocalFanart() const
2729 if (!HasVideoInfoTag())
2730 return ""; // nothing can be done
2731 CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
2732 return dbItem.GetLocalFanart();
2735 CStdString strFile2;
2736 CStdString strFile = m_strPath;
2740 URIUtils::GetParentPath(m_strPath,strPath);
2741 CStackDirectory dir;
2742 CStdString strPath2;
2743 strPath2 = dir.GetStackedTitlePath(strFile);
2744 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2),strFile);
2745 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
2746 CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-fanart"));
2747 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strFile2);
2749 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2751 CStdString strPath, strParent;
2752 URIUtils::GetDirectory(strFile,strPath);
2753 URIUtils::GetParentPath(strPath,strParent);
2754 URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
2757 // no local fanart available for these
2758 if (IsInternetStream()
2759 || URIUtils::IsUPnP(strFile)
2763 || (URIUtils::IsFTP(strFile) && !g_advancedSettings.m_bFTPThumbs)
2764 || m_strPath.IsEmpty())
2768 URIUtils::GetDirectory(strFile, strDir);
2770 if (strDir.IsEmpty())
2773 CFileItemList items;
2774 CDirectory::GetDirectory(strDir, items, g_settings.m_pictureExtensions, false, false, DIR_CACHE_ALWAYS, false, true);
2776 CStdStringArray fanarts;
2777 StringUtils::SplitString(g_advancedSettings.m_fanartImages, "|", fanarts);
2779 strFile = URIUtils::ReplaceExtension(strFile, "-fanart");
2780 fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile));
2782 if (!strFile2.IsEmpty())
2783 fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile2));
2785 for (unsigned int i = 0; i < fanarts.size(); ++i)
2787 for (int j = 0; j < items.Size(); j++)
2789 CStdString strCandidate = URIUtils::GetFileName(items[j]->m_strPath);
2790 URIUtils::RemoveExtension(strCandidate);
2791 CStdString strFanart = fanarts[i];
2792 URIUtils::RemoveExtension(strFanart);
2793 if (strCandidate.CompareNoCase(strFanart) == 0)
2794 return items[j]->m_strPath;
2801 CStdString CFileItem::GetCachedFanart() const
2803 // get the locally cached thumb
2806 if (!HasVideoInfoTag())
2808 if (!GetVideoInfoTag()->m_strArtist.IsEmpty())
2809 return GetCachedThumb(GetVideoInfoTag()->m_strArtist,g_settings.GetMusicFanartFolder());
2810 if (!m_bIsFolder && !GetVideoInfoTag()->m_strShowTitle.IsEmpty())
2812 CVideoDatabase database;
2814 int iShowId = database.GetTvShowId(GetVideoInfoTag()->m_strPath);
2815 CStdString showPath;
2816 database.GetFilePathById(iShowId,showPath,VIDEODB_CONTENT_TVSHOWS);
2817 return GetCachedThumb(showPath,g_settings.GetVideoFanartFolder());
2819 return GetCachedThumb(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath,g_settings.GetVideoFanartFolder());
2821 if (HasMusicInfoTag())
2822 return GetCachedThumb(GetMusicInfoTag()->GetArtist(),g_settings.GetMusicFanartFolder());
2824 return GetCachedThumb(m_strPath,g_settings.GetVideoFanartFolder());
2827 CStdString CFileItem::GetCachedThumb(const CStdString &path, const CStdString &path2, bool split)
2829 // get the locally cached thumb
2831 crc.ComputeFromLowerCase(path);
2837 hex.Format("%08x", (__int32)crc);
2838 thumb.Format("%c\\%08x.tbn", hex[0], (unsigned __int32)crc);
2841 thumb.Format("%08x.tbn", (unsigned __int32)crc);
2843 return URIUtils::AddFileToFolder(path2, thumb);
2846 /*void CFileItem::SetThumb()
2848 // we need to know the type of file at this point
2849 // as differing views have differing inheritance rules for thumbs:
2852 // Folders only use <foldername>/folder.jpg or <foldername>.tbn
2853 // Files use <filename>.tbn
2854 // * Thumbs are cached from here using file or folder path
2857 // Folders only use <foldername>/folder.jpg or <foldername>.tbn
2858 // Files use <filename>.tbn or the album/path cached thumb or inherit from the folder
2859 // * Thumbs are cached from here using file or folder path
2862 // Folders only use <foldername>/folder.jpg or <foldername>.tbn
2863 // Files use <filename>.tbn or the embedded xbe. Shortcuts have the additional step of the <thumbnail> tag to check
2864 // * Thumbs are cached from here using file or folder path
2867 // Folders use <foldername>/folder.jpg or <foldername>.tbn, or auto-generated from 4 images in the folder
2868 // Files use <filename>.tbn or a resized version of the picture
2869 // * Thumbs are cached from here using file or folder path
2873 bool CFileItem::LoadMusicTag()
2879 if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
2882 CMusicDatabase musicDatabase;
2883 if (musicDatabase.Open())
2886 if (musicDatabase.GetSongByFileName(m_strPath, song))
2888 GetMusicInfoTag()->SetSong(song);
2889 SetThumbnailImage(song.strThumb);
2892 musicDatabase.Close();
2894 // load tag from file
2895 CLog::Log(LOGDEBUG, "%s: loading tag information for file: %s", __FUNCTION__, m_strPath.c_str());
2896 CMusicInfoTagLoaderFactory factory;
2897 auto_ptr<IMusicInfoTagLoader> pLoader (factory.CreateLoader(m_strPath));
2898 if (NULL != pLoader.get())
2900 if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
2903 // no tag - try some other things
2906 // we have the tracknumber...
2907 int iTrack = GetMusicInfoTag()->GetTrackNumber();
2910 CStdString strText = g_localizeStrings.Get(554); // "Track"
2911 if (strText.GetAt(strText.size() - 1) != ' ')
2913 CStdString strTrack;
2914 strTrack.Format(strText + "%i", iTrack);
2915 GetMusicInfoTag()->SetTitle(strTrack);
2916 GetMusicInfoTag()->SetLoaded(true);
2922 CStdString fileName = URIUtils::GetFileName(m_strPath);
2923 URIUtils::RemoveExtension(fileName);
2924 for (unsigned int i = 0; i < g_advancedSettings.m_musicTagsFromFileFilters.size(); i++)
2926 CLabelFormatter formatter(g_advancedSettings.m_musicTagsFromFileFilters[i], "");
2927 if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
2929 GetMusicInfoTag()->SetLoaded(true);
2937 void CFileItemList::Swap(unsigned int item1, unsigned int item2)
2939 if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size())
2940 std::swap(m_items[item1], m_items[item2]);
2943 bool CFileItemList::UpdateItem(const CFileItem *item)
2945 if (!item) return false;
2946 CFileItemPtr oldItem = Get(item->m_strPath);
2952 void CFileItemList::AddSortMethod(SORT_METHOD sortMethod, int buttonLabel, const LABEL_MASKS &labelMasks)
2954 SORT_METHOD_DETAILS sort;
2955 sort.m_sortMethod=sortMethod;
2956 sort.m_buttonLabel=buttonLabel;
2957 sort.m_labelMasks=labelMasks;
2959 m_sortDetails.push_back(sort);
2962 void CFileItemList::SetReplaceListing(bool replace)
2964 m_replaceListing = replace;
2967 void CFileItemList::ClearSortState()
2969 m_sortMethod=SORT_METHOD_NONE;
2970 m_sortOrder=SORT_ORDER_NONE;
2973 CVideoInfoTag* CFileItem::GetVideoInfoTag()
2975 if (!m_videoInfoTag)
2976 m_videoInfoTag = new CVideoInfoTag;
2978 return m_videoInfoTag;
2981 CPictureInfoTag* CFileItem::GetPictureInfoTag()
2983 if (!m_pictureInfoTag)
2984 m_pictureInfoTag = new CPictureInfoTag;
2986 return m_pictureInfoTag;
2989 MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
2991 if (!m_musicInfoTag)
2992 m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
2994 return m_musicInfoTag;
2997 CStdString CFileItem::FindTrailer() const
2999 CStdString strFile2, strTrailer;
3000 CStdString strFile = m_strPath;
3004 URIUtils::GetParentPath(m_strPath,strPath);
3005 CStackDirectory dir;
3006 CStdString strPath2;
3007 strPath2 = dir.GetStackedTitlePath(strFile);
3008 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2),strFile);
3009 CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
3010 CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-trailer"));
3011 URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strFile2);
3013 if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
3015 CStdString strPath, strParent;
3016 URIUtils::GetDirectory(strFile,strPath);
3017 URIUtils::GetParentPath(strPath,strParent);
3018 URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
3021 // no local trailer available for these
3022 if (IsInternetStream()
3023 || URIUtils::IsUPnP(strFile)
3029 URIUtils::GetDirectory(strFile, strDir);
3030 CFileItemList items;
3031 CDirectory::GetDirectory(strDir, items, g_settings.m_videoExtensions, true, false, DIR_CACHE_ALWAYS, false, true);
3032 URIUtils::RemoveExtension(strFile);
3033 strFile += "-trailer";
3034 CStdString strFile3 = URIUtils::AddFileToFolder(strDir, "movie-trailer");
3036 // Precompile our REs
3037 VECCREGEXP matchRegExps;
3038 CRegExp tmpRegExp(true);
3039 const CStdStringArray& strMatchRegExps = g_advancedSettings.m_trailerMatchRegExps;
3041 CStdStringArray::const_iterator strRegExp = strMatchRegExps.begin();
3042 while (strRegExp != strMatchRegExps.end())
3044 if (tmpRegExp.RegComp(*strRegExp))
3046 matchRegExps.push_back(tmpRegExp);
3051 for (int i = 0; i < items.Size(); i++)
3053 CStdString strCandidate = items[i]->m_strPath;
3054 URIUtils::RemoveExtension(strCandidate);
3055 if (strCandidate.CompareNoCase(strFile) == 0 ||
3056 strCandidate.CompareNoCase(strFile2) == 0 ||
3057 strCandidate.CompareNoCase(strFile3) == 0)
3059 strTrailer = items[i]->m_strPath;
3064 VECCREGEXP::iterator expr = matchRegExps.begin();
3066 while (expr != matchRegExps.end())
3068 if (expr->RegFind(strCandidate) != -1)
3070 strTrailer = items[i]->m_strPath;
3082 int CFileItem::GetVideoContentType() const
3084 VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
3085 if (HasVideoInfoTag() && !GetVideoInfoTag()->m_strShowTitle.IsEmpty()) // tvshow
3086 type = VIDEODB_CONTENT_TVSHOWS;
3087 if (HasVideoInfoTag() && GetVideoInfoTag()->m_iSeason > -1 && !m_bIsFolder) // episode
3088 type = VIDEODB_CONTENT_EPISODES;
3089 if (HasVideoInfoTag() && !GetVideoInfoTag()->m_strArtist.IsEmpty())
3090 type = VIDEODB_CONTENT_MUSICVIDEOS;