[win32] cmake: make use of ADDONS_TO_BUILD in make-addons.bat
[vuplus_xbmc] / xbmc / FileItem.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "FileItem.h"
22 #include "guilib/LocalizeStrings.h"
23 #include "utils/StringUtils.h"
24 #include "utils/URIUtils.h"
25 #include "utils/Archive.h"
26 #include "Util.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"
41 #include "epg/Epg.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"
53 #include "URL.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"
61 #ifdef HAS_ASAP_CODEC
62 #include "cores/paplayer/ASAPCodec.h"
63 #endif
64
65 using namespace std;
66 using namespace XFILE;
67 using namespace PLAYLIST;
68 using namespace MUSIC_INFO;
69 using namespace PVR;
70 using namespace EPG;
71
72 CFileItem::CFileItem(const CSong& song)
73 {
74   Initialize();
75   SetFromSong(song);
76 }
77
78 CFileItem::CFileItem(const CURL &url, const CAlbum& album)
79 {
80   Initialize();
81
82   m_strPath = url.Get();
83   URIUtils::AddSlashAtEnd(m_strPath);
84   SetFromAlbum(album);
85 }
86
87 CFileItem::CFileItem(const std::string &path, const CAlbum& album)
88 {
89   Initialize();
90
91   m_strPath = path;
92   URIUtils::AddSlashAtEnd(m_strPath);
93   SetFromAlbum(album);
94 }
95
96 CFileItem::CFileItem(const CMusicInfoTag& music)
97 {
98   Initialize();
99   SetLabel(music.GetTitle());
100   m_strPath = music.GetURL();
101   m_bIsFolder = URIUtils::HasSlashAtEnd(m_strPath);
102   *GetMusicInfoTag() = music;
103   FillInDefaultIcon();
104   FillInMimeType(false);
105 }
106
107 CFileItem::CFileItem(const CVideoInfoTag& movie)
108 {
109   Initialize();
110   SetFromVideoInfoTag(movie);
111 }
112
113 CFileItem::CFileItem(const CEpgInfoTag& tag)
114 {
115   Initialize();
116
117   m_strPath = tag.Path();
118   m_bIsFolder = false;
119   *GetEPGInfoTag() = tag;
120   SetLabel(tag.Title());
121   m_strLabel2 = tag.Plot();
122   m_dateTime = tag.StartAsLocalTime();
123
124   if (!tag.Icon().empty())
125     SetIconImage(tag.Icon());
126   else if (tag.HasPVRChannel() && !tag.ChannelTag()->IconPath().empty())
127     SetIconImage(tag.ChannelTag()->IconPath());
128
129   FillInMimeType(false);
130 }
131
132 CFileItem::CFileItem(const CPVRChannel& channel)
133 {
134   Initialize();
135
136   CEpgInfoTag epgNow;
137   bool bHasEpgNow = channel.GetEPGNow(epgNow);
138
139   m_strPath = channel.Path();
140   m_bIsFolder = false;
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
146
147   if (channel.IsRadio())
148   {
149     CMusicInfoTag* musictag = GetMusicInfoTag();
150     if (musictag)
151     {
152       musictag->SetURL(channel.Path());
153       musictag->SetTitle(m_strLabel2);
154       musictag->SetArtist(channel.ChannelName());
155       musictag->SetAlbumArtist(channel.ChannelName());
156       if (bHasEpgNow)
157         musictag->SetGenre(epgNow.Genre());
158       musictag->SetDuration(bHasEpgNow ? epgNow.GetDuration() : 3600);
159       musictag->SetLoaded(true);
160       musictag->SetComment("");
161       musictag->SetLyrics("");
162     }
163   }
164
165   if (!channel.IconPath().empty())
166     SetIconImage(channel.IconPath());
167
168   SetProperty("channelid", channel.ChannelID());
169   SetProperty("path", channel.Path());
170   SetArt("thumb", channel.IconPath());
171
172   FillInMimeType(false);
173 }
174
175 CFileItem::CFileItem(const CPVRRecording& record)
176 {
177   Initialize();
178
179   m_strPath = record.m_strFileNameAndPath;
180   m_bIsFolder = false;
181   *GetPVRRecordingInfoTag() = record;
182   SetLabel(record.m_strTitle);
183   m_strLabel2 = record.m_strPlot;
184
185   FillInMimeType(false);
186 }
187
188 CFileItem::CFileItem(const CPVRTimerInfoTag& timer)
189 {
190   Initialize();
191
192   m_strPath = timer.Path();
193   m_bIsFolder = false;
194   *GetPVRTimerInfoTag() = timer;
195   SetLabel(timer.Title());
196   m_strLabel2 = timer.Summary();
197   m_dateTime = timer.StartAsLocalTime();
198
199   if (!timer.ChannelIcon().empty())
200     SetIconImage(timer.ChannelIcon());
201
202   FillInMimeType(false);
203 }
204
205 CFileItem::CFileItem(const CArtist& artist)
206 {
207   Initialize();
208   SetLabel(artist.strArtist);
209   m_strPath = artist.strArtist;
210   m_bIsFolder = true;
211   URIUtils::AddSlashAtEnd(m_strPath);
212   GetMusicInfoTag()->SetArtist(artist.strArtist);
213   FillInMimeType(false);
214 }
215
216 CFileItem::CFileItem(const CGenre& genre)
217 {
218   Initialize();
219   SetLabel(genre.strGenre);
220   m_strPath = genre.strGenre;
221   m_bIsFolder = true;
222   URIUtils::AddSlashAtEnd(m_strPath);
223   GetMusicInfoTag()->SetGenre(genre.strGenre);
224   FillInMimeType(false);
225 }
226
227 CFileItem::CFileItem(const CFileItem& item): CGUIListItem()
228 {
229   m_musicInfoTag = NULL;
230   m_videoInfoTag = NULL;
231   m_epgInfoTag = NULL;
232   m_pvrChannelInfoTag = NULL;
233   m_pvrRecordingInfoTag = NULL;
234   m_pvrTimerInfoTag = NULL;
235   m_pictureInfoTag = NULL;
236   *this = item;
237 }
238
239 CFileItem::CFileItem(const CGUIListItem& item)
240 {
241   Initialize();
242   // not particularly pretty, but it gets around the issue of Initialize() defaulting
243   // parameters in the CGUIListItem base class.
244   *((CGUIListItem *)this) = item;
245
246   FillInMimeType(false);
247 }
248
249 CFileItem::CFileItem(void)
250 {
251   Initialize();
252 }
253
254 CFileItem::CFileItem(const std::string& strLabel)
255     : CGUIListItem()
256 {
257   Initialize();
258   SetLabel(strLabel);
259 }
260
261 CFileItem::CFileItem(const CURL& path, bool bIsFolder)
262 {
263   Initialize();
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);
270 }
271
272 CFileItem::CFileItem(const std::string& strPath, bool bIsFolder)
273 {
274   Initialize();
275   m_strPath = strPath;
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);
281 }
282
283 CFileItem::CFileItem(const CMediaSource& share)
284 {
285   Initialize();
286   m_bIsFolder = true;
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());
294   SetLabel(label);
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);
302   if (IsDVD())
303     GetVideoInfoTag()->m_strFileNameAndPath = share.strDiskUniqueId; // share.strDiskUniqueId contains disc unique id
304   FillInMimeType(false);
305 }
306
307 CFileItem::~CFileItem(void)
308 {
309   delete m_musicInfoTag;
310   delete m_videoInfoTag;
311   delete m_epgInfoTag;
312   delete m_pvrChannelInfoTag;
313   delete m_pvrRecordingInfoTag;
314   delete m_pvrTimerInfoTag;
315   delete m_pictureInfoTag;
316
317   m_musicInfoTag = NULL;
318   m_videoInfoTag = NULL;
319   m_epgInfoTag = NULL;
320   m_pvrChannelInfoTag = NULL;
321   m_pvrRecordingInfoTag = NULL;
322   m_pvrTimerInfoTag = NULL;
323   m_pictureInfoTag = NULL;
324 }
325
326 const CFileItem& CFileItem::operator=(const CFileItem& item)
327 {
328   if (this == &item) return * this;
329   CGUIListItem::operator=(item);
330   m_bLabelPreformated=item.m_bLabelPreformated;
331   FreeMemory();
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())
339   {
340     m_musicInfoTag = GetMusicInfoTag();
341     if (m_musicInfoTag)
342       *m_musicInfoTag = *item.m_musicInfoTag;
343   }
344   else
345   {
346     delete m_musicInfoTag;
347     m_musicInfoTag = NULL;
348   }
349
350   if (item.HasVideoInfoTag())
351   {
352     m_videoInfoTag = GetVideoInfoTag();
353     if (m_videoInfoTag)
354       *m_videoInfoTag = *item.m_videoInfoTag;
355   }
356   else
357   {
358     delete m_videoInfoTag;
359     m_videoInfoTag = NULL;
360   }
361
362   if (item.HasEPGInfoTag())
363   {
364     m_epgInfoTag = GetEPGInfoTag();
365     if (m_epgInfoTag)
366       *m_epgInfoTag = *item.m_epgInfoTag;
367   }
368   else
369   {
370     if (m_epgInfoTag)
371       delete m_epgInfoTag;
372
373     m_epgInfoTag = NULL;
374   }
375
376   if (item.HasPVRChannelInfoTag())
377   {
378     m_pvrChannelInfoTag = GetPVRChannelInfoTag();
379     if (m_pvrChannelInfoTag)
380       *m_pvrChannelInfoTag = *item.m_pvrChannelInfoTag;
381   }
382   else
383   {
384     if (m_pvrChannelInfoTag)
385       delete m_pvrChannelInfoTag;
386
387     m_pvrChannelInfoTag = NULL;
388   }
389
390   if (item.HasPVRRecordingInfoTag())
391   {
392     m_pvrRecordingInfoTag = GetPVRRecordingInfoTag();
393     if (m_pvrRecordingInfoTag)
394       *m_pvrRecordingInfoTag = *item.m_pvrRecordingInfoTag;
395   }
396   else
397   {
398     if (m_pvrRecordingInfoTag)
399       delete m_pvrRecordingInfoTag;
400
401     m_pvrRecordingInfoTag = NULL;
402   }
403
404   if (item.HasPVRTimerInfoTag())
405   {
406     m_pvrTimerInfoTag = GetPVRTimerInfoTag();
407     if (m_pvrTimerInfoTag)
408       *m_pvrTimerInfoTag = *item.m_pvrTimerInfoTag;
409   }
410   else
411   {
412     if (m_pvrTimerInfoTag)
413       delete m_pvrTimerInfoTag;
414
415     m_pvrTimerInfoTag = NULL;
416   }
417
418   if (item.HasPictureInfoTag())
419   {
420     m_pictureInfoTag = GetPictureInfoTag();
421     if (m_pictureInfoTag)
422       *m_pictureInfoTag = *item.m_pictureInfoTag;
423   }
424   else
425   {
426     delete m_pictureInfoTag;
427     m_pictureInfoTag = NULL;
428   }
429
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;
446   return *this;
447 }
448
449 void CFileItem::Initialize()
450 {
451   m_musicInfoTag = NULL;
452   m_videoInfoTag = NULL;
453   m_epgInfoTag = NULL;
454   m_pvrChannelInfoTag = NULL;
455   m_pvrRecordingInfoTag = NULL;
456   m_pvrTimerInfoTag = NULL;
457   m_pictureInfoTag = NULL;
458   m_bLabelPreformated=false;
459   m_bIsAlbum = false;
460   m_dwSize = 0;
461   m_bIsParentFolder=false;
462   m_bIsShareOrDrive = false;
463   m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
464   m_lStartOffset = 0;
465   m_lStartPartNumber = 1;
466   m_lEndOffset = 0;
467   m_iprogramCount = 0;
468   m_idepth = 1;
469   m_iLockMode = LOCK_MODE_EVERYONE;
470   m_iBadPwdCount = 0;
471   m_iHasLock = 0;
472   m_bCanQueue=true;
473   m_specialSort = SortSpecialNone;
474 }
475
476 void CFileItem::Reset()
477 {
478   // CGUIListItem members...
479   m_strLabel2.clear();
480   SetLabel("");
481   FreeIcons();
482   m_overlayIcon = ICON_OVERLAY_NONE;
483   m_bSelected = false;
484   m_bIsFolder = false;
485
486   m_strDVDLabel.clear();
487   m_strTitle.clear();
488   m_strPath.clear();
489   m_dateTime.Reset();
490   m_strLockCode.clear();
491   m_mimetype.clear();
492   delete m_musicInfoTag;
493   m_musicInfoTag=NULL;
494   delete m_videoInfoTag;
495   m_videoInfoTag=NULL;
496   delete m_epgInfoTag;
497   m_epgInfoTag=NULL;
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;
506   m_extrainfo.clear();
507   ClearProperties();
508
509   Initialize();
510   SetInvalid();
511 }
512
513 void CFileItem::Archive(CArchive& ar)
514 {
515   CGUIListItem::Archive(ar);
516
517   if (ar.IsStoring())
518   {
519     ar << m_bIsParentFolder;
520     ar << m_bLabelPreformated;
521     ar << m_strPath;
522     ar << m_bIsShareOrDrive;
523     ar << m_iDriveType;
524     ar << m_dateTime;
525     ar << m_dwSize;
526     ar << m_strDVDLabel;
527     ar << m_strTitle;
528     ar << m_iprogramCount;
529     ar << m_idepth;
530     ar << m_lStartOffset;
531     ar << m_lStartPartNumber;
532     ar << m_lEndOffset;
533     ar << m_iLockMode;
534     ar << m_strLockCode;
535     ar << m_iBadPwdCount;
536
537     ar << m_bCanQueue;
538     ar << m_mimetype;
539     ar << m_extrainfo;
540     ar << m_specialSort;
541
542     if (m_musicInfoTag)
543     {
544       ar << 1;
545       ar << *m_musicInfoTag;
546     }
547     else
548       ar << 0;
549     if (m_videoInfoTag)
550     {
551       ar << 1;
552       ar << *m_videoInfoTag;
553     }
554     else
555       ar << 0;
556     if (m_pictureInfoTag)
557     {
558       ar << 1;
559       ar << *m_pictureInfoTag;
560     }
561     else
562       ar << 0;
563   }
564   else
565   {
566     ar >> m_bIsParentFolder;
567     ar >> m_bLabelPreformated;
568     ar >> m_strPath;
569     ar >> m_bIsShareOrDrive;
570     ar >> m_iDriveType;
571     ar >> m_dateTime;
572     ar >> m_dwSize;
573     ar >> m_strDVDLabel;
574     ar >> m_strTitle;
575     ar >> m_iprogramCount;
576     ar >> m_idepth;
577     ar >> m_lStartOffset;
578     ar >> m_lStartPartNumber;
579     ar >> m_lEndOffset;
580     int temp;
581     ar >> temp;
582     m_iLockMode = (LockType)temp;
583     ar >> m_strLockCode;
584     ar >> m_iBadPwdCount;
585
586     ar >> m_bCanQueue;
587     ar >> m_mimetype;
588     ar >> m_extrainfo;
589     ar >> temp;
590     m_specialSort = (SortSpecial)temp;
591
592     int iType;
593     ar >> iType;
594     if (iType == 1)
595       ar >> *GetMusicInfoTag();
596     ar >> iType;
597     if (iType == 1)
598       ar >> *GetVideoInfoTag();
599     ar >> iType;
600     if (iType == 1)
601       ar >> *GetPictureInfoTag();
602
603     SetInvalid();
604   }
605 }
606
607 void CFileItem::Serialize(CVariant& value) const
608 {
609   //CGUIListItem::Serialize(value["CGUIListItem"]);
610
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;
619
620   if (m_musicInfoTag)
621     (*m_musicInfoTag).Serialize(value["musicInfoTag"]);
622
623   if (m_videoInfoTag)
624     (*m_videoInfoTag).Serialize(value["videoInfoTag"]);
625
626   if (m_pictureInfoTag)
627     (*m_pictureInfoTag).Serialize(value["pictureInfoTag"]);
628 }
629
630 void CFileItem::ToSortable(SortItem &sortable, Field field) const
631 {
632   switch (field)
633   {
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
645   default: break;
646   }
647
648   if (HasMusicInfoTag())
649     GetMusicInfoTag()->ToSortable(sortable, field);
650
651   if (HasVideoInfoTag())
652   {
653     GetVideoInfoTag()->ToSortable(sortable, field);
654
655     if (GetVideoInfoTag()->m_type == MediaTypeTvShow)
656     {
657       if (field == FieldNumberOfEpisodes && HasProperty("totalepisodes"))
658         sortable[FieldNumberOfEpisodes] = GetProperty("totalepisodes");
659       if (field == FieldNumberOfWatchedEpisodes && HasProperty("unwatchedepisodes"))
660         sortable[FieldNumberOfWatchedEpisodes] = GetProperty("unwatchedepisodes");
661     }
662   }
663
664   if (HasPictureInfoTag())
665     GetPictureInfoTag()->ToSortable(sortable, field);
666
667   if (HasPVRChannelInfoTag())
668     GetPVRChannelInfoTag()->ToSortable(sortable, field);
669 }
670
671 void CFileItem::ToSortable(SortItem &sortable, const Fields &fields) const
672 {
673   Fields::const_iterator it;
674   for (it = fields.begin(); it != fields.end(); it++)
675     ToSortable(sortable, *it);
676
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;
682 }
683
684 bool CFileItem::Exists(bool bUseCache /* = true */) const
685 {
686   if (m_strPath.empty()
687    || IsPath("add")
688    || IsInternetStream()
689    || IsParentFolder()
690    || IsVirtualDirectoryRoot()
691    || IsPlugin())
692     return true;
693
694   if (IsVideoDb() && HasVideoInfoTag())
695   {
696     CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
697     return dbItem.Exists();
698   }
699
700   std::string strPath = m_strPath;
701
702   if (URIUtils::IsMultiPath(strPath))
703     strPath = CMultiPathDirectory::GetFirstPath(strPath);
704
705   if (URIUtils::IsStack(strPath))
706     strPath = CStackDirectory::GetFirstStackedFile(strPath);
707
708   if (m_bIsFolder)
709     return CDirectory::Exists(strPath, bUseCache);
710   else
711     return CFile::Exists(strPath, bUseCache);
712
713   return false;
714 }
715
716 bool CFileItem::IsVideo() const
717 {
718   /* check preset mime type */
719   if( StringUtils::StartsWithNoCase(m_mimetype, "video/") )
720     return true;
721
722   if (HasVideoInfoTag()) return true;
723   if (HasMusicInfoTag()) return false;
724   if (HasPictureInfoTag()) return false;
725   if (IsPVRRecording())  return true;
726
727   if (IsHDHomeRun() || IsTuxBox() || URIUtils::IsDVD(m_strPath) || IsSlingbox())
728     return true;
729
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") )
737      return true;
738   }
739
740   return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_videoExtensions);
741 }
742
743 bool CFileItem::IsEPG() const
744 {
745   if (HasEPGInfoTag()) return true; /// is this enough?
746   return false;
747 }
748
749 bool CFileItem::IsPVRChannel() const
750 {
751   if (HasPVRChannelInfoTag()) return true; /// is this enough?
752   return false;
753 }
754
755 bool CFileItem::IsPVRRecording() const
756 {
757   if (HasPVRRecordingInfoTag()) return true; /// is this enough?
758   return false;
759 }
760
761 bool CFileItem::IsPVRTimer() const
762 {
763   if (HasPVRTimerInfoTag()) return true; /// is this enough?
764   return false;
765 }
766
767 bool CFileItem::IsDiscStub() const
768 {
769   if (IsVideoDb() && HasVideoInfoTag())
770   {
771     CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
772     return dbItem.IsDiscStub();
773   }
774
775   return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_discStubExtensions);
776 }
777
778 bool CFileItem::IsAudio() const
779 {
780   /* check preset mime type */
781   if( StringUtils::StartsWithNoCase(m_mimetype, "audio/") )
782     return true;
783
784   if (HasMusicInfoTag()) return true;
785   if (HasVideoInfoTag()) return false;
786   if (HasPictureInfoTag()) return false;
787   if (IsCDDA()) return true;
788
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") )
795      return true;
796   }
797
798   return URIUtils::HasExtension(m_strPath, g_advancedSettings.m_musicExtensions);
799 }
800
801 bool CFileItem::IsKaraoke() const
802 {
803   if ( !IsAudio())
804     return false;
805
806   return CKaraokeLyricsFactory::HasLyrics( m_strPath );
807 }
808
809 bool CFileItem::IsPicture() const
810 {
811   if( StringUtils::StartsWithNoCase(m_mimetype, "image/") )
812     return true;
813
814   if (HasPictureInfoTag()) return true;
815   if (HasMusicInfoTag()) return false;
816   if (HasVideoInfoTag()) return false;
817
818   return CUtil::IsPicture(m_strPath);
819 }
820
821 bool CFileItem::IsLyrics() const
822 {
823   return URIUtils::HasExtension(m_strPath, ".cdg|.lrc");
824 }
825
826 bool CFileItem::IsCUESheet() const
827 {
828   return URIUtils::HasExtension(m_strPath, ".cue");
829 }
830
831 bool CFileItem::IsInternetStream(const bool bStrictCheck /* = false */) const
832 {
833   if (HasProperty("IsHTTPDirectory"))
834     return false;
835
836   return URIUtils::IsInternetStream(m_strPath, bStrictCheck);
837 }
838
839 bool CFileItem::IsFileFolder(EFileFolderType types) const
840 {
841   EFileFolderType always_type = EFILEFOLDER_TYPE_ALWAYS;
842
843   /* internet streams are not directly expanded */
844   if(IsInternetStream())
845     always_type = EFILEFOLDER_TYPE_ONCLICK;
846
847
848   if(types & always_type)
849   {
850     if( IsSmartPlayList()
851     || (IsPlayList() && g_advancedSettings.m_playlistAsFolders)
852     || IsAPK()
853     || IsZIP()
854     || IsRAR()
855     || IsRSS()
856     || IsType(".ogg|.oga|.nsf|.sid|.sap|.xsp")
857 #if defined(TARGET_ANDROID)
858     || IsType(".apk")
859 #endif
860 #ifdef HAS_ASAP_CODEC
861     || ASAPCodec::IsSupportedFormat(URIUtils::GetExtension(m_strPath))
862 #endif
863     )
864       return true;
865   }
866
867   if(types & EFILEFOLDER_TYPE_ONBROWSE)
868   {
869     if((IsPlayList() && !g_advancedSettings.m_playlistAsFolders)
870     || IsDVDImage())
871       return true;
872   }
873
874   return false;
875 }
876
877
878 bool CFileItem::IsSmartPlayList() const
879 {
880   if (HasProperty("library.smartplaylist") && GetProperty("library.smartplaylist").asBoolean())
881     return true;
882
883   return URIUtils::HasExtension(m_strPath, ".xsp");
884 }
885
886 bool CFileItem::IsLibraryFolder() const
887 {
888   if (HasProperty("library.filter") && GetProperty("library.filter").asBoolean())
889     return true;
890
891   return URIUtils::IsLibraryFolder(m_strPath);
892 }
893
894 bool CFileItem::IsPlayList() const
895 {
896   return CPlayListFactory::IsPlaylist(*this);
897 }
898
899 bool CFileItem::IsPythonScript() const
900 {
901   return URIUtils::HasExtension(m_strPath, ".py");
902 }
903
904 bool CFileItem::IsType(const char *ext) const
905 {
906   return URIUtils::HasExtension(m_strPath, ext);
907 }
908
909 bool CFileItem::IsNFO() const
910 {
911   return URIUtils::HasExtension(m_strPath, ".nfo");
912 }
913
914 bool CFileItem::IsDVDImage() const
915 {
916   return URIUtils::HasExtension(m_strPath, ".img|.iso|.nrg");
917 }
918
919 bool CFileItem::IsOpticalMediaFile() const
920 {
921   bool found = IsDVDFile(false, true);
922   if (found)
923     return true;
924   return IsBDFile();
925 }
926
927 bool CFileItem::IsDVDFile(bool bVobs /*= true*/, bool bIfos /*= true*/) const
928 {
929   std::string strFileName = URIUtils::GetFileName(m_strPath);
930   if (bIfos)
931   {
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;
934   }
935   if (bVobs)
936   {
937     if (StringUtils::EqualsNoCase(strFileName, "video_ts.vob")) return true;
938     if (StringUtils::StartsWithNoCase(strFileName, "vts_") && StringUtils::EndsWithNoCase(strFileName, ".vob")) return true;
939   }
940
941   return false;
942 }
943
944 bool CFileItem::IsBDFile() const
945 {
946   std::string strFileName = URIUtils::GetFileName(m_strPath);
947   return (StringUtils::EqualsNoCase(strFileName, "index.bdmv"));
948 }
949
950 bool CFileItem::IsRAR() const
951 {
952   return URIUtils::IsRAR(m_strPath);
953 }
954
955 bool CFileItem::IsAPK() const
956 {
957   return URIUtils::IsAPK(m_strPath);
958 }
959
960 bool CFileItem::IsZIP() const
961 {
962   return URIUtils::IsZIP(m_strPath);
963 }
964
965 bool CFileItem::IsCBZ() const
966 {
967   return URIUtils::HasExtension(m_strPath, ".cbz");
968 }
969
970 bool CFileItem::IsCBR() const
971 {
972   return URIUtils::HasExtension(m_strPath, ".cbr");
973 }
974
975 bool CFileItem::IsRSS() const
976 {
977   return StringUtils::StartsWithNoCase(m_strPath, "rss://") || URIUtils::HasExtension(m_strPath, ".rss")
978       || m_mimetype == "application/rss+xml";
979 }
980
981 bool CFileItem::IsAndroidApp() const
982 {
983   return URIUtils::IsAndroidApp(m_strPath);
984 }
985
986 bool CFileItem::IsStack() const
987 {
988   return URIUtils::IsStack(m_strPath);
989 }
990
991 bool CFileItem::IsPlugin() const
992 {
993   return URIUtils::IsPlugin(m_strPath);
994 }
995
996 bool CFileItem::IsScript() const
997 {
998   return URIUtils::IsScript(m_strPath);
999 }
1000
1001 bool CFileItem::IsAddonsPath() const
1002 {
1003   return URIUtils::IsAddonsPath(m_strPath);
1004 }
1005
1006 bool CFileItem::IsSourcesPath() const
1007 {
1008   return URIUtils::IsSourcesPath(m_strPath);
1009 }
1010
1011 bool CFileItem::IsMultiPath() const
1012 {
1013   return URIUtils::IsMultiPath(m_strPath);
1014 }
1015
1016 bool CFileItem::IsCDDA() const
1017 {
1018   return URIUtils::IsCDDA(m_strPath);
1019 }
1020
1021 bool CFileItem::IsDVD() const
1022 {
1023   return URIUtils::IsDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1024 }
1025
1026 bool CFileItem::IsOnDVD() const
1027 {
1028   return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
1029 }
1030
1031 bool CFileItem::IsNfs() const
1032 {
1033   return URIUtils::IsNfs(m_strPath);
1034 }
1035
1036 bool CFileItem::IsAfp() const
1037 {
1038   return URIUtils::IsAfp(m_strPath);
1039 }
1040
1041 bool CFileItem::IsOnLAN() const
1042 {
1043   return URIUtils::IsOnLAN(m_strPath);
1044 }
1045
1046 bool CFileItem::IsISO9660() const
1047 {
1048   return URIUtils::IsISO9660(m_strPath);
1049 }
1050
1051 bool CFileItem::IsRemote() const
1052 {
1053   return URIUtils::IsRemote(m_strPath);
1054 }
1055
1056 bool CFileItem::IsSmb() const
1057 {
1058   return URIUtils::IsSmb(m_strPath);
1059 }
1060
1061 bool CFileItem::IsURL() const
1062 {
1063   return URIUtils::IsURL(m_strPath);
1064 }
1065
1066 bool CFileItem::IsDAAP() const
1067 {
1068   return URIUtils::IsDAAP(m_strPath);
1069 }
1070
1071 bool CFileItem::IsTuxBox() const
1072 {
1073   return URIUtils::IsTuxBox(m_strPath);
1074 }
1075
1076 bool CFileItem::IsMythTV() const
1077 {
1078   return URIUtils::IsMythTV(m_strPath);
1079 }
1080
1081 bool CFileItem::IsHDHomeRun() const
1082 {
1083   return URIUtils::IsHDHomeRun(m_strPath);
1084 }
1085
1086 bool CFileItem::IsSlingbox() const
1087 {
1088   return URIUtils::IsSlingbox(m_strPath);
1089 }
1090
1091 bool CFileItem::IsVTP() const
1092 {
1093   return URIUtils::IsVTP(m_strPath);
1094 }
1095
1096 bool CFileItem::IsPVR() const
1097 {
1098   return CUtil::IsPVR(m_strPath);
1099 }
1100
1101 bool CFileItem::IsLiveTV() const
1102 {
1103   return URIUtils::IsLiveTV(m_strPath);
1104 }
1105
1106 bool CFileItem::IsHD() const
1107 {
1108   return URIUtils::IsHD(m_strPath);
1109 }
1110
1111 bool CFileItem::IsMusicDb() const
1112 {
1113   return URIUtils::IsMusicDb(m_strPath);
1114 }
1115
1116 bool CFileItem::IsVideoDb() const
1117 {
1118   return URIUtils::IsVideoDb(m_strPath);
1119 }
1120
1121 bool CFileItem::IsVirtualDirectoryRoot() const
1122 {
1123   return (m_bIsFolder && m_strPath.empty());
1124 }
1125
1126 bool CFileItem::IsRemovable() const
1127 {
1128   return IsOnDVD() || IsCDDA() || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE;
1129 }
1130
1131 bool CFileItem::IsReadOnly() const
1132 {
1133   if (IsParentFolder()) return true;
1134   if (m_bIsShareOrDrive) return true;
1135   return !CUtil::SupportsWriteFileOperations(m_strPath);
1136 }
1137
1138 void CFileItem::FillInDefaultIcon()
1139 {
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
1149   //
1150   // for folders
1151   //   for .. folders the default picture for parent folder
1152   //   for other folders the defaultFolder.png
1153
1154   if (GetIconImage().empty())
1155   {
1156     if (!m_bIsFolder)
1157     {
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.
1162        */
1163       if (IsPVRChannel())
1164       {
1165         if (GetPVRChannelInfoTag()->IsRadio())
1166           SetIconImage("DefaultAudio.png");
1167         else
1168           SetIconImage("DefaultVideo.png");
1169       }
1170       else if ( IsLiveTV() )
1171       {
1172         // Live TV Channel
1173         SetIconImage("DefaultVideo.png");
1174       }
1175       else if ( URIUtils::IsArchive(m_strPath) )
1176       { // archive
1177         SetIconImage("DefaultFile.png");
1178       }
1179       else if ( IsAudio() )
1180       {
1181         // audio
1182         SetIconImage("DefaultAudio.png");
1183       }
1184       else if ( IsVideo() )
1185       {
1186         // video
1187         SetIconImage("DefaultVideo.png");
1188       }
1189       else if (IsPVRRecording())
1190       {
1191         SetIconImage("DefaultVideo.png");
1192       }
1193       else if (IsPVRTimer())
1194       {
1195         SetIconImage("DefaultVideo.png");
1196       }
1197       else if ( IsPicture() )
1198       {
1199         // picture
1200         SetIconImage("DefaultPicture.png");
1201       }
1202       else if ( IsPlayList() )
1203       {
1204         SetIconImage("DefaultPlaylist.png");
1205       }
1206       else if ( IsPythonScript() )
1207       {
1208         SetIconImage("DefaultScript.png");
1209       }
1210       else
1211       {
1212         // default icon for unknown file type
1213         SetIconImage("DefaultFile.png");
1214       }
1215     }
1216     else
1217     {
1218       if ( IsPlayList() )
1219       {
1220         SetIconImage("DefaultPlaylist.png");
1221       }
1222       else if (IsParentFolder())
1223       {
1224         SetIconImage("DefaultFolderBack.png");
1225       }
1226       else
1227       {
1228         SetIconImage("DefaultFolder.png");
1229       }
1230     }
1231   }
1232   // Set the icon overlays (if applicable)
1233   if (!HasOverlay())
1234   {
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);
1239   }
1240 }
1241
1242 void CFileItem::RemoveExtension()
1243 {
1244   if (m_bIsFolder)
1245     return;
1246   std::string strLabel = GetLabel();
1247   URIUtils::RemoveExtension(strLabel);
1248   SetLabel(strLabel);
1249 }
1250
1251 void CFileItem::CleanString()
1252 {
1253   if (IsLiveTV())
1254     return;
1255
1256   std::string strLabel = GetLabel();
1257   std::string strTitle, strTitleAndYear, strYear;
1258   CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, true );
1259   SetLabel(strTitleAndYear);
1260 }
1261
1262 void CFileItem::SetLabel(const std::string &strLabel)
1263 {
1264   if (strLabel=="..")
1265   {
1266     m_bIsParentFolder=true;
1267     m_bIsFolder=true;
1268     m_specialSort = SortSpecialOnTop;
1269     SetLabelPreformated(true);
1270   }
1271   CGUIListItem::SetLabel(strLabel);
1272 }
1273
1274 void CFileItem::SetFileSizeLabel()
1275 {
1276   if( m_bIsFolder && m_dwSize == 0 )
1277     SetLabel2("");
1278   else
1279     SetLabel2(StringUtils::SizeToString(m_dwSize));
1280 }
1281
1282 bool CFileItem::CanQueue() const
1283 {
1284   return m_bCanQueue;
1285 }
1286
1287 void CFileItem::SetCanQueue(bool bYesNo)
1288 {
1289   m_bCanQueue=bYesNo;
1290 }
1291
1292 bool CFileItem::IsParentFolder() const
1293 {
1294   return m_bIsParentFolder;
1295 }
1296
1297 void CFileItem::FillInMimeType(bool lookup /*= true*/)
1298 {
1299   // TODO: adapt this to use CMime::GetMimeType()
1300   if (m_mimetype.empty())
1301   {
1302     if( m_bIsFolder )
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://"))
1309     {
1310       // If lookup is false, bail out early to leave mime type empty
1311       if (!lookup)
1312         return;
1313
1314       CCurlFile::GetMimeType(GetURL(), m_mimetype);
1315
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");
1321
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);
1328     }
1329     else
1330       m_mimetype = CMime::GetMimeType(*this);
1331
1332     // if it's still empty set to an unknown type
1333     if (m_mimetype.empty())
1334       m_mimetype = "application/octet-stream";
1335   }
1336
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:");
1340 }
1341
1342 bool CFileItem::IsSamePath(const CFileItem *item) const
1343 {
1344   if (!item)
1345     return false;
1346
1347   if (item->GetPath() == m_strPath)
1348   {
1349     if (item->HasProperty("item_start") || HasProperty("item_start"))
1350       return (item->GetProperty("item_start") == GetProperty("item_start"));
1351     return true;
1352   }
1353   if (HasVideoInfoTag() && item->HasVideoInfoTag())
1354   {
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));        
1358   }
1359   if (IsMusicDb() && HasMusicInfoTag())
1360   {
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);
1365   }
1366   if (IsVideoDb() && HasVideoInfoTag())
1367   {
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);
1372   }
1373   if (item->IsMusicDb() && item->HasMusicInfoTag())
1374   {
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);
1379   }
1380   if (item->IsVideoDb() && item->HasVideoInfoTag())
1381   {
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);
1386   }
1387   if (HasProperty("original_listitem_url"))
1388     return (GetProperty("original_listitem_url") == item->GetPath());
1389   return false;
1390 }
1391
1392 bool CFileItem::IsAlbum() const
1393 {
1394   return m_bIsAlbum;
1395 }
1396
1397 void CFileItem::UpdateInfo(const CFileItem &item, bool replaceLabels /*=true*/)
1398 {
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);
1406     SetInvalid();
1407   }
1408   if (item.HasMusicInfoTag())
1409   {
1410     *GetMusicInfoTag() = *item.GetMusicInfoTag();
1411     SetInvalid();
1412   }
1413   if (item.HasPictureInfoTag())
1414   {
1415     *GetPictureInfoTag() = *item.GetPictureInfoTag();
1416     SetInvalid();
1417   }
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);
1427 }
1428
1429 void CFileItem::SetFromVideoInfoTag(const CVideoInfoTag &video)
1430 {
1431   if (!video.m_strTitle.empty())
1432     SetLabel(video.m_strTitle);
1433   if (video.m_strFileNameAndPath.empty())
1434   {
1435     m_strPath = video.m_strPath;
1436     URIUtils::AddSlashAtEnd(m_strPath);
1437     m_bIsFolder = true;
1438   }
1439   else
1440   {
1441     m_strPath = video.m_strFileNameAndPath;
1442     m_bIsFolder = false;
1443   }
1444   
1445   *GetVideoInfoTag() = video;
1446   if (video.m_iSeason == 0)
1447     SetProperty("isspecial", "true");
1448   FillInDefaultIcon();
1449   FillInMimeType(false);
1450 }
1451
1452 void CFileItem::SetFromAlbum(const CAlbum &album)
1453 {
1454   if (!album.strAlbum.empty())
1455     SetLabel(album.strAlbum);
1456   m_bIsFolder = true;
1457   m_strLabel2 = StringUtils::Join(album.artist, g_advancedSettings.m_musicItemSeparator);
1458   GetMusicInfoTag()->SetAlbum(album);
1459   m_bIsAlbum = true;
1460   CMusicDatabase::SetPropertiesFromAlbum(*this,album);
1461   FillInMimeType(false);
1462 }
1463
1464 void CFileItem::SetFromSong(const CSong &song)
1465 {
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);
1478 }
1479
1480 std::string CFileItem::GetOpticalMediaPath() const
1481 {
1482   std::string path;
1483   std::string dvdPath;
1484   path = URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS.IFO");
1485   if (CFile::Exists(path))
1486     dvdPath = path;
1487   else
1488   {
1489     dvdPath = URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS");
1490     path = URIUtils::AddFileToFolder(dvdPath, "VIDEO_TS.IFO");
1491     dvdPath.clear();
1492     if (CFile::Exists(path))
1493       dvdPath = path;
1494   }
1495 #ifdef HAVE_LIBBLURAY
1496   if (dvdPath.empty())
1497   {
1498     path = URIUtils::AddFileToFolder(GetPath(), "index.bdmv");
1499     if (CFile::Exists(path))
1500       dvdPath = path;
1501     else
1502     {
1503       dvdPath = URIUtils::AddFileToFolder(GetPath(), "BDMV");
1504       path = URIUtils::AddFileToFolder(dvdPath, "index.bdmv");
1505       dvdPath.clear();
1506       if (CFile::Exists(path))
1507         dvdPath = path;
1508     }
1509   }
1510 #endif
1511   return dvdPath;
1512 }
1513
1514 /*
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.
1520  */
1521 void CFileItem::SetURL(const CURL& url)
1522 {
1523   m_strPath = url.Get();
1524 }
1525
1526 const CURL CFileItem::GetURL() const
1527 {
1528   CURL url(m_strPath);
1529   return url;
1530 }
1531
1532 bool CFileItem::IsURL(const CURL& url) const
1533 {
1534   return IsPath(url.Get());
1535 }
1536
1537 bool CFileItem::IsPath(const std::string& path) const
1538 {
1539   return URIUtils::PathEquals(m_strPath, path);
1540 }
1541
1542 /////////////////////////////////////////////////////////////////////////////////
1543 /////
1544 ///// CFileItemList
1545 /////
1546 //////////////////////////////////////////////////////////////////////////////////
1547
1548 CFileItemList::CFileItemList()
1549 {
1550   m_fastLookup = false;
1551   m_bIsFolder = true;
1552   m_cacheToDisc = CACHE_IF_SLOW;
1553   m_sortIgnoreFolders = false;
1554   m_replaceListing = false;
1555 }
1556
1557 CFileItemList::CFileItemList(const std::string& strPath) : CFileItem(strPath, true)
1558 {
1559   m_fastLookup = false;
1560   m_cacheToDisc = CACHE_IF_SLOW;
1561   m_sortIgnoreFolders = false;
1562   m_replaceListing = false;
1563 }
1564
1565 CFileItemList::~CFileItemList()
1566 {
1567   Clear();
1568 }
1569
1570 CFileItemPtr CFileItemList::operator[] (int iItem)
1571 {
1572   return Get(iItem);
1573 }
1574
1575 const CFileItemPtr CFileItemList::operator[] (int iItem) const
1576 {
1577   return Get(iItem);
1578 }
1579
1580 CFileItemPtr CFileItemList::operator[] (const std::string& strPath)
1581 {
1582   return Get(strPath);
1583 }
1584
1585 const CFileItemPtr CFileItemList::operator[] (const std::string& strPath) const
1586 {
1587   return Get(strPath);
1588 }
1589
1590 void CFileItemList::SetFastLookup(bool fastLookup)
1591 {
1592   CSingleLock lock(m_lock);
1593
1594   if (fastLookup && !m_fastLookup)
1595   { // generate the map
1596     m_map.clear();
1597     for (unsigned int i=0; i < m_items.size(); i++)
1598     {
1599       CFileItemPtr pItem = m_items[i];
1600       m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1601     }
1602   }
1603   if (!fastLookup && m_fastLookup)
1604     m_map.clear();
1605   m_fastLookup = fastLookup;
1606 }
1607
1608 bool CFileItemList::Contains(const std::string& fileName) const
1609 {
1610   CSingleLock lock(m_lock);
1611
1612   if (m_fastLookup)
1613     return m_map.find(fileName) != m_map.end();
1614
1615   // slow method...
1616   for (unsigned int i = 0; i < m_items.size(); i++)
1617   {
1618     const CFileItemPtr pItem = m_items[i];
1619     if (pItem->IsPath(fileName))
1620       return true;
1621   }
1622   return false;
1623 }
1624
1625 void CFileItemList::Clear()
1626 {
1627   CSingleLock lock(m_lock);
1628
1629   ClearItems();
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;
1637   m_content.clear();
1638 }
1639
1640 void CFileItemList::ClearItems()
1641 {
1642   CSingleLock lock(m_lock);
1643   // make sure we free the memory of the items (these are GUIControls which may have allocated resources)
1644   FreeMemory();
1645   for (unsigned int i = 0; i < m_items.size(); i++)
1646   {
1647     CFileItemPtr item = m_items[i];
1648     item->FreeMemory();
1649   }
1650   m_items.clear();
1651   m_map.clear();
1652 }
1653
1654 void CFileItemList::Add(const CFileItemPtr &pItem)
1655 {
1656   CSingleLock lock(m_lock);
1657
1658   m_items.push_back(pItem);
1659   if (m_fastLookup)
1660   {
1661     m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1662   }
1663 }
1664
1665 void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition)
1666 {
1667   CSingleLock lock(m_lock);
1668
1669   if (itemPosition >= 0)
1670   {
1671     m_items.insert(m_items.begin()+itemPosition, pItem);
1672   }
1673   else
1674   {
1675     m_items.insert(m_items.begin()+(m_items.size()+itemPosition), pItem);
1676   }
1677   if (m_fastLookup)
1678   {
1679     m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
1680   }
1681 }
1682
1683 void CFileItemList::Remove(CFileItem* pItem)
1684 {
1685   CSingleLock lock(m_lock);
1686
1687   for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it)
1688   {
1689     if (pItem == it->get())
1690     {
1691       m_items.erase(it);
1692       if (m_fastLookup)
1693       {
1694         m_map.erase(pItem->GetPath());
1695       }
1696       break;
1697     }
1698   }
1699 }
1700
1701 void CFileItemList::Remove(int iItem)
1702 {
1703   CSingleLock lock(m_lock);
1704
1705   if (iItem >= 0 && iItem < (int)Size())
1706   {
1707     CFileItemPtr pItem = *(m_items.begin() + iItem);
1708     if (m_fastLookup)
1709     {
1710       m_map.erase(pItem->GetPath());
1711     }
1712     m_items.erase(m_items.begin() + iItem);
1713   }
1714 }
1715
1716 void CFileItemList::Append(const CFileItemList& itemlist)
1717 {
1718   CSingleLock lock(m_lock);
1719
1720   for (int i = 0; i < itemlist.Size(); ++i)
1721     Add(itemlist[i]);
1722 }
1723
1724 void CFileItemList::Assign(const CFileItemList& itemlist, bool append)
1725 {
1726   CSingleLock lock(m_lock);
1727   if (!append)
1728     Clear();
1729   Append(itemlist);
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;
1738 }
1739
1740 bool CFileItemList::Copy(const CFileItemList& items, bool copyItems /* = true */)
1741 {
1742   // assign all CFileItem parts
1743   *(CFileItem*)this = *(CFileItem*)&items;
1744
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;
1753
1754   if (copyItems)
1755   {
1756     // make a copy of each item
1757     for (int i = 0; i < items.Size(); i++)
1758     {
1759       CFileItemPtr newItem(new CFileItem(*items[i]));
1760       Add(newItem);
1761     }
1762   }
1763
1764   return true;
1765 }
1766
1767 CFileItemPtr CFileItemList::Get(int iItem)
1768 {
1769   CSingleLock lock(m_lock);
1770
1771   if (iItem > -1 && iItem < (int)m_items.size())
1772     return m_items[iItem];
1773
1774   return CFileItemPtr();
1775 }
1776
1777 const CFileItemPtr CFileItemList::Get(int iItem) const
1778 {
1779   CSingleLock lock(m_lock);
1780
1781   if (iItem > -1 && iItem < (int)m_items.size())
1782     return m_items[iItem];
1783
1784   return CFileItemPtr();
1785 }
1786
1787 CFileItemPtr CFileItemList::Get(const std::string& strPath)
1788 {
1789   CSingleLock lock(m_lock);
1790
1791   if (m_fastLookup)
1792   {
1793     IMAPFILEITEMS it=m_map.find(strPath);
1794     if (it != m_map.end())
1795       return it->second;
1796
1797     return CFileItemPtr();
1798   }
1799   // slow method...
1800   for (unsigned int i = 0; i < m_items.size(); i++)
1801   {
1802     CFileItemPtr pItem = m_items[i];
1803     if (pItem->IsPath(strPath))
1804       return pItem;
1805   }
1806
1807   return CFileItemPtr();
1808 }
1809
1810 const CFileItemPtr CFileItemList::Get(const std::string& strPath) const
1811 {
1812   CSingleLock lock(m_lock);
1813
1814   if (m_fastLookup)
1815   {
1816     map<std::string, CFileItemPtr>::const_iterator it=m_map.find(strPath);
1817     if (it != m_map.end())
1818       return it->second;
1819
1820     return CFileItemPtr();
1821   }
1822   // slow method...
1823   for (unsigned int i = 0; i < m_items.size(); i++)
1824   {
1825     CFileItemPtr pItem = m_items[i];
1826     if (pItem->IsPath(strPath))
1827       return pItem;
1828   }
1829
1830   return CFileItemPtr();
1831 }
1832
1833 int CFileItemList::Size() const
1834 {
1835   CSingleLock lock(m_lock);
1836   return (int)m_items.size();
1837 }
1838
1839 bool CFileItemList::IsEmpty() const
1840 {
1841   CSingleLock lock(m_lock);
1842   return (m_items.size() <= 0);
1843 }
1844
1845 void CFileItemList::Reserve(int iCount)
1846 {
1847   CSingleLock lock(m_lock);
1848   m_items.reserve(iCount);
1849 }
1850
1851 void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func)
1852 {
1853   CSingleLock lock(m_lock);
1854   std::stable_sort(m_items.begin(), m_items.end(), func);
1855 }
1856
1857 void CFileItemList::FillSortFields(FILEITEMFILLFUNC func)
1858 {
1859   CSingleLock lock(m_lock);
1860   std::for_each(m_items.begin(), m_items.end(), func);
1861 }
1862
1863 void CFileItemList::Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute sortAttributes /* = SortAttributeNone */)
1864 {
1865   if (sortBy == SortByNone ||
1866      (m_sortDescription.sortBy == sortBy && m_sortDescription.sortOrder == sortOrder &&
1867       m_sortDescription.sortAttributes == sortAttributes))
1868     return;
1869
1870   SortDescription sorting;
1871   sorting.sortBy = sortBy;
1872   sorting.sortOrder = sortOrder;
1873   sorting.sortAttributes = sortAttributes;
1874
1875   Sort(sorting);
1876   m_sortDescription = sorting;
1877 }
1878
1879 void CFileItemList::Sort(SortDescription sortDescription)
1880 {
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);
1890
1891   if (sortDescription.sortBy == SortByNone ||
1892      (m_sortDescription.sortBy == sortDescription.sortBy && m_sortDescription.sortOrder == sortDescription.sortOrder &&
1893       m_sortDescription.sortAttributes == sortDescription.sortAttributes))
1894     return;
1895
1896   if (m_sortIgnoreFolders)
1897     sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders);
1898
1899   const Fields fields = SortUtils::GetFieldsForSorting(sortDescription.sortBy);
1900   SortItems sortItems((size_t)Size());
1901   for (int index = 0; index < Size(); index++)
1902   {
1903     sortItems[index] = boost::shared_ptr<SortItem>(new SortItem);
1904     m_items[index]->ToSortable(*sortItems[index], fields);
1905     (*sortItems[index])[FieldId] = index;
1906   }
1907
1908   // do the sorting
1909   SortUtils::Sort(sortDescription, sortItems);
1910
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++)
1915   {
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());
1919
1920     sortedFileItems.push_back(item);
1921   }
1922
1923   // replace the current list with the re-ordered one
1924   m_items.assign(sortedFileItems.begin(), sortedFileItems.end());
1925 }
1926
1927 void CFileItemList::Randomize()
1928 {
1929   CSingleLock lock(m_lock);
1930   random_shuffle(m_items.begin(), m_items.end());
1931 }
1932
1933 void CFileItemList::Archive(CArchive& ar)
1934 {
1935   CSingleLock lock(m_lock);
1936   if (ar.IsStoring())
1937   {
1938     CFileItem::Archive(ar);
1939
1940     int i = 0;
1941     if (m_items.size() > 0 && m_items[0]->IsParentFolder())
1942       i = 1;
1943
1944     ar << (int)(m_items.size() - i);
1945
1946     ar << m_fastLookup;
1947
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;
1953
1954     ar << (int)m_sortDetails.size();
1955     for (unsigned int j = 0; j < m_sortDetails.size(); ++j)
1956     {
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;
1966     }
1967
1968     ar << m_content;
1969
1970     for (; i < (int)m_items.size(); ++i)
1971     {
1972       CFileItemPtr pItem = m_items[i];
1973       ar << *pItem;
1974     }
1975   }
1976   else
1977   {
1978     CFileItemPtr pParent;
1979     if (!IsEmpty())
1980     {
1981       CFileItemPtr pItem=m_items[0];
1982       if (pItem->IsParentFolder())
1983         pParent.reset(new CFileItem(*pItem));
1984     }
1985
1986     SetFastLookup(false);
1987     Clear();
1988
1989
1990     CFileItem::Archive(ar);
1991
1992     int iSize = 0;
1993     ar >> iSize;
1994     if (iSize <= 0)
1995       return ;
1996
1997     if (pParent)
1998     {
1999       m_items.reserve(iSize + 1);
2000       m_items.push_back(pParent);
2001     }
2002     else
2003       m_items.reserve(iSize);
2004
2005     bool fastLookup=false;
2006     ar >> fastLookup;
2007
2008     int tempint;
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);
2018
2019     unsigned int detailSize = 0;
2020     ar >> detailSize;
2021     for (unsigned int j = 0; j < detailSize; ++j)
2022     {
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);
2036     }
2037
2038     ar >> m_content;
2039
2040     for (int i = 0; i < iSize; ++i)
2041     {
2042       CFileItemPtr pItem(new CFileItem);
2043       ar >> *pItem;
2044       Add(pItem);
2045     }
2046
2047     SetFastLookup(fastLookup);
2048   }
2049 }
2050
2051 void CFileItemList::FillInDefaultIcons()
2052 {
2053   CSingleLock lock(m_lock);
2054   for (int i = 0; i < (int)m_items.size(); ++i)
2055   {
2056     CFileItemPtr pItem = m_items[i];
2057     pItem->FillInDefaultIcon();
2058   }
2059 }
2060
2061 int CFileItemList::GetFolderCount() const
2062 {
2063   CSingleLock lock(m_lock);
2064   int nFolderCount = 0;
2065   for (int i = 0; i < (int)m_items.size(); i++)
2066   {
2067     CFileItemPtr pItem = m_items[i];
2068     if (pItem->m_bIsFolder)
2069       nFolderCount++;
2070   }
2071
2072   return nFolderCount;
2073 }
2074
2075 int CFileItemList::GetObjectCount() const
2076 {
2077   CSingleLock lock(m_lock);
2078
2079   int numObjects = (int)m_items.size();
2080   if (numObjects && m_items[0]->IsParentFolder())
2081     numObjects--;
2082
2083   return numObjects;
2084 }
2085
2086 int CFileItemList::GetFileCount() const
2087 {
2088   CSingleLock lock(m_lock);
2089   int nFileCount = 0;
2090   for (int i = 0; i < (int)m_items.size(); i++)
2091   {
2092     CFileItemPtr pItem = m_items[i];
2093     if (!pItem->m_bIsFolder)
2094       nFileCount++;
2095   }
2096
2097   return nFileCount;
2098 }
2099
2100 int CFileItemList::GetSelectedCount() const
2101 {
2102   CSingleLock lock(m_lock);
2103   int count = 0;
2104   for (int i = 0; i < (int)m_items.size(); i++)
2105   {
2106     CFileItemPtr pItem = m_items[i];
2107     if (pItem->IsSelected())
2108       count++;
2109   }
2110
2111   return count;
2112 }
2113
2114 void CFileItemList::FilterCueItems()
2115 {
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++)
2121   {
2122     CFileItemPtr pItem = m_items[i];
2123     if (!pItem->m_bIsFolder)
2124     { // see if it's a .CUE sheet
2125       if (pItem->IsCUESheet())
2126       {
2127         CCueDocument cuesheet;
2128         if (cuesheet.Parse(pItem->GetPath()))
2129         {
2130           VECSONGS newitems;
2131           cuesheet.GetSongs(newitems);
2132
2133           std::vector<CStdString> MediaFileVec;
2134           cuesheet.GetMediaFiles(MediaFileVec);
2135
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++)
2138           {
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)
2145             {
2146               // try file in same dir, not matching case...
2147               if (Contains(strMediaFile))
2148               {
2149                 bFoundMediaFile = true;
2150               }
2151               else
2152               {
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))
2158                 {
2159                   bFoundMediaFile = true;
2160                 }
2161                 else
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)
2165                   {
2166                     strMediaFile = URIUtils::ReplaceExtension(pItem->GetPath(), *i);
2167                     CFileItem item(strMediaFile, false);
2168                     if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile))
2169                     {
2170                       bFoundMediaFile = true;
2171                       break;
2172                     }
2173                   }
2174                 }
2175               }
2176             }
2177             if (bFoundMediaFile)
2178             {
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.
2182               CMusicInfoTag tag;
2183               auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(strMediaFile));
2184               if (NULL != pLoader.get())
2185               {
2186                 // get id3tag
2187                 pLoader->Load(strMediaFile, tag);
2188               }
2189               // fill in any missing entries from underlying media file
2190               for (int j = 0; j < (int)newitems.size(); j++)
2191               {
2192                 CSong song = newitems[j];
2193                 // only for songs that actually match the current media file
2194                 if (song.strFileName == fileFromCue)
2195                 {
2196                   // we might have a new media file from the above matching code
2197                   song.strFileName = strMediaFile;
2198                   if (tag.Loaded())
2199                   {
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();
2210                   }
2211                   if (!song.iDuration && tag.GetDuration() > 0)
2212                   { // must be the last song
2213                     song.iDuration = (tag.GetDuration() * 75 - song.iStartOffset + 37) / 75;
2214                   }
2215                   // add this item to the list
2216                   itemstoadd.push_back(song);
2217                 }
2218               }
2219             }
2220             else
2221             { // remove the .cue sheet from the directory
2222               itemstodelete.push_back(pItem->GetPath());
2223             }
2224           }
2225         }
2226         else
2227         { // remove the .cue sheet from the directory (can't parse it - no point listing it)
2228           itemstodelete.push_back(pItem->GetPath());
2229         }
2230       }
2231     }
2232   }
2233   // now delete the .CUE files and underlying media files.
2234   for (int i = 0; i < (int)itemstodelete.size(); i++)
2235   {
2236     for (int j = 0; j < (int)m_items.size(); j++)
2237     {
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);
2242         break;
2243       }
2244     }
2245   }
2246   // and add the files from the .CUE sheet
2247   for (int i = 0; i < (int)itemstoadd.size(); i++)
2248   {
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);
2252   }
2253 }
2254
2255 // Remove the extensions from the filenames
2256 void CFileItemList::RemoveExtensions()
2257 {
2258   CSingleLock lock(m_lock);
2259   for (int i = 0; i < Size(); ++i)
2260     m_items[i]->RemoveExtension();
2261 }
2262
2263 void CFileItemList::Stack(bool stackFiles /* = true */)
2264 {
2265   CSingleLock lock(m_lock);
2266
2267   // not allowed here
2268   if (IsVirtualDirectoryRoot() || IsLiveTV() || IsSourcesPath())
2269     return;
2270
2271   SetProperty("isstacked", true);
2272
2273   // items needs to be sorted for stuff below to work properly
2274   Sort(SortByLabel, SortOrderAscending);
2275
2276   StackFolders();
2277
2278   if (stackFiles)
2279     StackFiles();
2280 }
2281
2282 void CFileItemList::StackFolders()
2283 {
2284   // Precompile our REs
2285   VECCREGEXP folderRegExps;
2286   CRegExp folderRegExp(true, CRegExp::autoUtf8);
2287   const vector<string>& strFolderRegExps = g_advancedSettings.m_folderStackRegExps;
2288
2289   vector<string>::const_iterator strExpression = strFolderRegExps.begin();
2290   while (strExpression != strFolderRegExps.end())
2291   {
2292     if (!folderRegExp.RegComp(*strExpression))
2293       CLog::Log(LOGERROR, "%s: Invalid folder stack RegExp:'%s'", __FUNCTION__, strExpression->c_str());
2294     else
2295       folderRegExps.push_back(folderRegExp);
2296
2297     strExpression++;
2298   }
2299
2300   // stack folders
2301   for (int i = 0; i < Size(); i++)
2302   {
2303     CFileItemPtr item = Get(i);
2304     // combined the folder checks
2305     if (item->m_bIsFolder)
2306     {
2307       // only check known fast sources?
2308       // NOTES:
2309       // 1. rars and zips may be on slow sources? is this supposed to be allowed?
2310       if( !item->IsRemote()
2311         || item->IsSmb()
2312         || item->IsNfs() 
2313         || item->IsAfp()
2314         || URIUtils::IsInRAR(item->GetPath())
2315         || URIUtils::IsInZIP(item->GetPath())
2316         || URIUtils::IsOnLAN(item->GetPath())
2317         )
2318       {
2319         // stack cd# folders if contains only a single video file
2320
2321         bool bMatch(false);
2322
2323         VECCREGEXP::iterator expr = folderRegExps.begin();
2324         while (!bMatch && expr != folderRegExps.end())
2325         {
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);
2328           if (bMatch)
2329           {
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
2334             int nFiles = 0;
2335             int index = -1;
2336             for (int j = 0; j < items.Size(); j++)
2337             {
2338               if (!items[j]->m_bIsFolder)
2339               {
2340                 nFiles++;
2341                 index = j;
2342               }
2343
2344               if (nFiles > 1)
2345                 break;
2346             }
2347
2348             if (nFiles == 1)
2349               *item = *items[index];
2350           }
2351           expr++;
2352         }
2353
2354         // check for dvd folders
2355         if (!bMatch)
2356         {
2357           std::string dvdPath = item->GetOpticalMediaPath();
2358
2359           if (!dvdPath.empty())
2360           {
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 */
2367           }
2368         }
2369       }
2370     }
2371   }
2372 }
2373
2374 void CFileItemList::StackFiles()
2375 {
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())
2382   {
2383     if (tmpRegExp.RegComp(*strRegExp))
2384     {
2385       if (tmpRegExp.GetCaptureTotal() == 4)
2386         stackRegExps.push_back(tmpRegExp);
2387       else
2388         CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have 4 captures.", strRegExp->c_str());
2389     }
2390     strRegExp++;
2391   }
2392
2393   // now stack the files, some of which may be from the previous stack iteration
2394   int i = 0;
2395   while (i < Size())
2396   {
2397     CFileItemPtr item1 = Get(i);
2398
2399     // skip folders, nfo files, playlists
2400     if (item1->m_bIsFolder
2401       || item1->IsParentFolder()
2402       || item1->IsNFO()
2403       || item1->IsPlayList()
2404       )
2405     {
2406       // increment index
2407       i++;
2408       continue;
2409     }
2410
2411     int64_t               size        = 0;
2412     size_t                offset      = 0;
2413     std::string           stackName;
2414     std::string           file1;
2415     std::string           filePath;
2416     vector<int>           stack;
2417     VECCREGEXP::iterator  expr        = stackRegExps.begin();
2418
2419     URIUtils::Split(item1->GetPath(), filePath, file1);
2420     if (URIUtils::HasEncodedFilename(CURL(filePath)))
2421       file1 = CURL::Decode(file1);
2422
2423     int j;
2424     while (expr != stackRegExps.end())
2425     {
2426       if (expr->RegFind(file1, offset) != -1)
2427       {
2428         std::string Title1      = expr->GetMatch(1),
2429                     Volume1     = expr->GetMatch(2),
2430                     Ignore1     = expr->GetMatch(3),
2431                     Extension1  = expr->GetMatch(4);
2432         if (offset)
2433           Title1 = file1.substr(0, expr->GetSubStart(2));
2434         j = i + 1;
2435         while (j < Size())
2436         {
2437           CFileItemPtr item2 = Get(j);
2438
2439           // skip folders, nfo files, playlists
2440           if (item2->m_bIsFolder
2441             || item2->IsParentFolder()
2442             || item2->IsNFO()
2443             || item2->IsPlayList()
2444             )
2445           {
2446             // increment index
2447             j++;
2448             continue;
2449           }
2450
2451           std::string file2, filePath2;
2452           URIUtils::Split(item2->GetPath(), filePath2, file2);
2453           if (URIUtils::HasEncodedFilename(CURL(filePath2)) )
2454             file2 = CURL::Decode(file2);
2455
2456           if (expr->RegFind(file2, offset) != -1)
2457           {
2458             std::string  Title2      = expr->GetMatch(1),
2459                         Volume2     = expr->GetMatch(2),
2460                         Ignore2     = expr->GetMatch(3),
2461                         Extension2  = expr->GetMatch(4);
2462             if (offset)
2463               Title2 = file2.substr(0, expr->GetSubStart(2));
2464             if (StringUtils::EqualsNoCase(Title1, Title2))
2465             {
2466               if (!StringUtils::EqualsNoCase(Volume1, Volume2))
2467               {
2468                 if (StringUtils::EqualsNoCase(Ignore1, Ignore2) &&
2469                     StringUtils::EqualsNoCase(Extension1, Extension2))
2470                 {
2471                   if (stack.size() == 0)
2472                   {
2473                     stackName = Title1 + Ignore1 + Extension1;
2474                     stack.push_back(i);
2475                     size += item1->m_dwSize;
2476                   }
2477                   stack.push_back(j);
2478                   size += item2->m_dwSize;
2479                 }
2480                 else // Sequel
2481                 {
2482                   offset = 0;
2483                   expr++;
2484                   break;
2485                 }
2486               }
2487               else if (!StringUtils::EqualsNoCase(Ignore1, Ignore2)) // False positive, try again with offset
2488               {
2489                 offset = expr->GetSubStart(3);
2490                 break;
2491               }
2492               else // Extension mismatch
2493               {
2494                 offset = 0;
2495                 expr++;
2496                 break;
2497               }
2498             }
2499             else // Title mismatch
2500             {
2501               offset = 0;
2502               expr++;
2503               break;
2504             }
2505           }
2506           else // No match 2, next expression
2507           {
2508             offset = 0;
2509             expr++;
2510             break;
2511           }
2512           j++;
2513         }
2514         if (j == Size())
2515           expr = stackRegExps.end();
2516       }
2517       else // No match 1
2518       {
2519         offset = 0;
2520         expr++;
2521       }
2522       if (stack.size() > 1)
2523       {
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();
2529         else
2530         {
2531           CStackDirectory dir;
2532           stackPath = dir.ConstructStackPath(*this, stack);
2533         }
2534         item1->SetPath(stackPath);
2535         // clean up list
2536         for (unsigned k = 1; k < stack.size(); k++)
2537           Remove(i+1);
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);
2543
2544         item1->SetLabel(stackName);
2545         item1->m_dwSize = size;
2546         break;
2547       }
2548     }
2549     i++;
2550   }
2551 }
2552
2553 bool CFileItemList::Load(int windowID)
2554 {
2555   CFile file;
2556   if (file.Open(GetDiscFileCache(windowID)))
2557   {
2558     CArchive ar(&file, CArchive::load);
2559     ar >> *this;
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");
2562     ar.Close();
2563     file.Close();
2564     return true;
2565   }
2566
2567   return false;
2568 }
2569
2570 bool CFileItemList::Save(int windowID)
2571 {
2572   int iSize = Size();
2573   if (iSize <= 0)
2574     return false;
2575
2576   CLog::Log(LOGDEBUG,"Saving fileitems [%s]", CURL::GetRedacted(GetPath()).c_str());
2577
2578   CFile file;
2579   if (file.OpenForWrite(GetDiscFileCache(windowID), true)) // overwrite always
2580   {
2581     CArchive ar(&file, CArchive::store);
2582     ar << *this;
2583     CLog::Log(LOGDEBUG,"  -- items: %i, sort method: %i, ascending: %s", iSize, m_sortDescription.sortBy, m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false");
2584     ar.Close();
2585     file.Close();
2586     return true;
2587   }
2588
2589   return false;
2590 }
2591
2592 void CFileItemList::RemoveDiscCache(int windowID) const
2593 {
2594   std::string cacheFile(GetDiscFileCache(windowID));
2595   if (CFile::Exists(cacheFile))
2596   {
2597     CLog::Log(LOGDEBUG,"Clearing cached fileitems [%s]",GetPath().c_str());
2598     CFile::Delete(cacheFile);
2599   }
2600 }
2601
2602 std::string CFileItemList::GetDiscFileCache(int windowID) const
2603 {
2604   std::string strPath(GetPath());
2605   URIUtils::RemoveSlashAtEnd(strPath);
2606
2607   Crc32 crc;
2608   crc.ComputeFromLowerCase(strPath);
2609
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);
2619   else if (windowID)
2620     cacheFile = StringUtils::Format("special://temp/%i-%08x.fi", windowID, (unsigned __int32)crc);
2621   else
2622     cacheFile = StringUtils::Format("special://temp/%08x.fi", (unsigned __int32)crc);
2623   return cacheFile;
2624 }
2625
2626 bool CFileItemList::AlwaysCache() const
2627 {
2628   // some database folders are always cached
2629   if (IsMusicDb())
2630     return CMusicDatabaseDirectory::CanCache(GetPath());
2631   if (IsVideoDb())
2632     return CVideoDatabaseDirectory::CanCache(GetPath());
2633   if (IsEPG())
2634     return true; // always cache
2635   return false;
2636 }
2637
2638 std::string CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */, bool fallbackToFolder /* = false */) const
2639 {
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)
2647    || IsPlugin()
2648    || IsAddonsPath()
2649    || IsParentFolder()
2650    || IsMusicDb())
2651     return "";
2652
2653   // we first check for <filename>.tbn or <foldername>.tbn
2654   std::string fileThumb(GetTBNFile());
2655   if (CFile::Exists(fileThumb))
2656     return fileThumb;
2657
2658   // Fall back to folder thumb, if requested
2659   if (!m_bIsFolder && fallbackToFolder)
2660   {
2661     CFileItem item(URIUtils::GetDirectory(m_strPath), true);
2662     return item.GetUserMusicThumb(alwaysCheckRemote);
2663   }
2664
2665   // if a folder, check for folder.jpg
2666   if (m_bIsFolder && !IsFileFolder() && (!IsRemote() || alwaysCheckRemote || CSettings::Get().GetBool("musicfiles.findremotethumbs")))
2667   {
2668     vector<string> thumbs = StringUtils::Split(g_advancedSettings.m_musicThumbs, "|");
2669     for (vector<string>::const_iterator i = thumbs.begin(); i != thumbs.end(); ++i)
2670     {
2671       std::string folderThumb(GetFolderThumb(*i));
2672       if (CFile::Exists(folderThumb))
2673       {
2674         return folderThumb;
2675       }
2676     }
2677   }
2678   // No thumb found
2679   return "";
2680 }
2681
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
2686 {
2687   std::string thumbFile;
2688   std::string strFile = m_strPath;
2689
2690   if (IsStack())
2691   {
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))
2698       return strReturn;
2699
2700     strFile = URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)));
2701   }
2702
2703   if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2704   {
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));
2709   }
2710
2711   CURL url(strFile);
2712   strFile = url.GetFileName();
2713
2714   if (m_bIsFolder && !IsFileFolder())
2715     URIUtils::RemoveSlashAtEnd(strFile);
2716
2717   if (!strFile.empty())
2718   {
2719     if (m_bIsFolder && !IsFileFolder())
2720       thumbFile = strFile + ".tbn"; // folder, so just add ".tbn"
2721     else
2722       thumbFile = URIUtils::ReplaceExtension(strFile, ".tbn");
2723     url.SetFileName(thumbFile);
2724     thumbFile = url.Get();
2725   }
2726   return thumbFile;
2727 }
2728
2729 bool CFileItem::SkipLocalArt() const
2730 {
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)
2738        || IsPlugin()
2739        || IsAddonsPath()
2740        || IsParentFolder()
2741        || IsLiveTV()
2742        || IsDVD());
2743 }
2744
2745 std::string CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) const
2746 {
2747   if (SkipLocalArt())
2748     return "";
2749
2750   std::string thumb;
2751   if (!m_bIsFolder)
2752   {
2753     thumb = GetLocalArt(artFile, false);
2754     if (!thumb.empty() && CFile::Exists(thumb))
2755       return thumb;
2756   }
2757   if ((useFolder || (m_bIsFolder && !IsFileFolder())) && !artFile.empty())
2758   {
2759     std::string thumb2 = GetLocalArt(artFile, true);
2760     if (!thumb2.empty() && thumb2 != thumb && CFile::Exists(thumb2))
2761       return thumb2;
2762   }
2763   return "";
2764 }
2765
2766 std::string CFileItem::GetLocalArt(const std::string &artFile, bool useFolder) const
2767 {
2768   // no retrieving of empty art files from folders
2769   if (useFolder && artFile.empty())
2770     return "";
2771
2772   std::string strFile = m_strPath;
2773   if (IsStack())
2774   {
2775 /*    CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
2776     std::string localArt = item.GetLocalArt(artFile);
2777     return localArt;
2778     */
2779     std::string strPath;
2780     URIUtils::GetParentPath(m_strPath,strPath);
2781     strFile = URIUtils::AddFileToFolder(strPath, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)));
2782   }
2783
2784   if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2785   {
2786     std::string strPath = URIUtils::GetDirectory(strFile);
2787     std::string strParent;
2788     URIUtils::GetParentPath(strPath,strParent);
2789     strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(strFile));
2790   }
2791
2792   if (IsMultiPath())
2793     strFile = CMultiPathDirectory::GetFirstPath(m_strPath);
2794
2795   if (IsOpticalMediaFile())
2796   { // optical media files should be treated like folders
2797     useFolder = true;
2798     strFile = GetLocalMetadataPath();
2799   }
2800   else if (useFolder && !(m_bIsFolder && !IsFileFolder()))
2801     strFile = URIUtils::GetDirectory(strFile);
2802
2803   if (strFile.empty()) // empty filepath -> nothing to find
2804     return "";
2805
2806   if (useFolder)
2807   {
2808     if (!artFile.empty())
2809       return URIUtils::AddFileToFolder(strFile, artFile);
2810   }
2811   else
2812   {
2813     if (artFile.empty()) // old thumbnail matching
2814       return URIUtils::ReplaceExtension(strFile, ".tbn");
2815     else
2816       return URIUtils::ReplaceExtension(strFile, "-" + artFile);
2817   }
2818   return "";
2819 }
2820
2821 std::string CFileItem::GetFolderThumb(const std::string &folderJPG /* = "folder.jpg" */) const
2822 {
2823   std::string strFolder = m_strPath;
2824
2825   if (IsStack() ||
2826       URIUtils::IsInRAR(strFolder) ||
2827       URIUtils::IsInZIP(strFolder))
2828   {
2829     URIUtils::GetParentPath(m_strPath,strFolder);
2830   }
2831
2832   if (IsMultiPath())
2833     strFolder = CMultiPathDirectory::GetFirstPath(m_strPath);
2834
2835   return URIUtils::AddFileToFolder(strFolder, folderJPG);
2836 }
2837
2838 std::string CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const
2839 {
2840   if (IsLabelPreformated())
2841     return GetLabel();
2842
2843   if (m_pvrRecordingInfoTag)
2844     return m_pvrRecordingInfoTag->m_strTitle;
2845   else if (CUtil::IsTVRecording(m_strPath))
2846   {
2847     std::string title = CPVRRecording::GetTitleFromURL(m_strPath);
2848     if (!title.empty())
2849       return title;
2850   }
2851
2852   std::string strMovieName = GetBaseMoviePath(bUseFolderNames);
2853
2854   if (URIUtils::IsStack(strMovieName))
2855     strMovieName = CStackDirectory::GetStackedTitlePath(strMovieName);
2856
2857   URIUtils::RemoveSlashAtEnd(strMovieName);
2858
2859   return CURL::Decode(URIUtils::GetFileName(strMovieName));
2860 }
2861
2862 std::string CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
2863 {
2864   std::string strMovieName = m_strPath;
2865
2866   if (IsMultiPath())
2867     strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
2868
2869   if (IsOpticalMediaFile())
2870     return GetLocalMetadataPath();
2871
2872   if ((!m_bIsFolder || URIUtils::IsInArchive(m_strPath)) && bUseFolderNames)
2873   {
2874     std::string name2(strMovieName);
2875     URIUtils::GetParentPath(name2,strMovieName);
2876     if (URIUtils::IsInArchive(m_strPath))
2877     {
2878       std::string strArchivePath;
2879       URIUtils::GetParentPath(strMovieName, strArchivePath);
2880       strMovieName = strArchivePath;
2881     }
2882   }
2883
2884   return strMovieName;
2885 }
2886
2887 std::string CFileItem::GetLocalFanart() const
2888 {
2889   if (IsVideoDb())
2890   {
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();
2895   }
2896
2897   std::string strFile2;
2898   std::string strFile = m_strPath;
2899   if (IsStack())
2900   {
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));
2910   }
2911   if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
2912   {
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));
2917   }
2918
2919   // no local fanart available for these
2920   if (IsInternetStream()
2921    || URIUtils::IsUPnP(strFile)
2922    || URIUtils::IsBluray(strFile)
2923    || IsLiveTV()
2924    || IsPlugin()
2925    || IsAddonsPath()
2926    || IsDVD()
2927    || (URIUtils::IsFTP(strFile) && !g_advancedSettings.m_bFTPThumbs)
2928    || m_strPath.empty())
2929     return "";
2930
2931   std::string strDir = URIUtils::GetDirectory(strFile);
2932
2933   if (strDir.empty())
2934     return "";
2935
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);
2943   }
2944
2945   vector<string> fanarts = StringUtils::Split(g_advancedSettings.m_fanartImages, "|");
2946
2947   strFile = URIUtils::ReplaceExtension(strFile, "-fanart");
2948   fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile));
2949
2950   if (!strFile2.empty())
2951     fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile2));
2952
2953   for (vector<string>::const_iterator i = fanarts.begin(); i != fanarts.end(); ++i)
2954   {
2955     for (int j = 0; j < items.Size(); j++)
2956     {
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;
2963     }
2964   }
2965
2966   return "";
2967 }
2968
2969 std::string CFileItem::GetLocalMetadataPath() const
2970 {
2971   if (m_bIsFolder && !IsFileFolder())
2972     return m_strPath;
2973
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);
2981   }
2982   return parent;
2983 }
2984
2985 bool CFileItem::LoadMusicTag()
2986 {
2987   // not audio
2988   if (!IsAudio())
2989     return false;
2990   // already loaded?
2991   if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
2992     return true;
2993   // check db
2994   CMusicDatabase musicDatabase;
2995   if (musicDatabase.Open())
2996   {
2997     CSong song;
2998     if (musicDatabase.GetSongByFileName(m_strPath, song))
2999     {
3000       GetMusicInfoTag()->SetSong(song);
3001       SetArt("thumb", song.strThumb);
3002       return true;
3003     }
3004     musicDatabase.Close();
3005   }
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())
3011   {
3012     if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
3013       return true;
3014   }
3015   // no tag - try some other things
3016   if (IsCDDA())
3017   {
3018     // we have the tracknumber...
3019     int iTrack = GetMusicInfoTag()->GetTrackNumber();
3020     if (iTrack >= 1)
3021     {
3022       std::string strText = g_localizeStrings.Get(554); // "Track"
3023       if (!strText.empty() && strText[strText.size() - 1] != ' ')
3024         strText += " ";
3025       std::string strTrack = StringUtils::Format((strText + "%i").c_str(), iTrack);
3026       GetMusicInfoTag()->SetTitle(strTrack);
3027       GetMusicInfoTag()->SetLoaded(true);
3028       return true;
3029     }
3030   }
3031   else
3032   {
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++)
3036     {
3037       CLabelFormatter formatter(g_advancedSettings.m_musicTagsFromFileFilters[i], "");
3038       if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
3039       {
3040         GetMusicInfoTag()->SetLoaded(true);
3041         return true;
3042       }
3043     }
3044   }
3045   return false;
3046 }
3047
3048 void CFileItemList::Swap(unsigned int item1, unsigned int item2)
3049 {
3050   if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size())
3051     std::swap(m_items[item1], m_items[item2]);
3052 }
3053
3054 bool CFileItemList::UpdateItem(const CFileItem *item)
3055 {
3056   if (!item) return false;
3057
3058   CSingleLock lock(m_lock);
3059   for (unsigned int i = 0; i < m_items.size(); i++)
3060   {
3061     CFileItemPtr pItem = m_items[i];
3062     if (pItem->IsSamePath(item))
3063     {
3064       pItem->UpdateInfo(*item);
3065       return true;
3066     }
3067   }
3068   return false;
3069 }
3070
3071 void CFileItemList::AddSortMethod(SortBy sortBy, int buttonLabel, const LABEL_MASKS &labelMasks, SortAttribute sortAttributes /* = SortAttributeNone */)
3072 {
3073   AddSortMethod(sortBy, sortAttributes, buttonLabel, labelMasks);
3074 }
3075
3076 void CFileItemList::AddSortMethod(SortBy sortBy, SortAttribute sortAttributes, int buttonLabel, const LABEL_MASKS &labelMasks)
3077 {
3078   SortDescription sorting;
3079   sorting.sortBy = sortBy;
3080   sorting.sortAttributes = sortAttributes;
3081
3082   AddSortMethod(sorting, buttonLabel, labelMasks);
3083 }
3084
3085 void CFileItemList::AddSortMethod(SortDescription sortDescription, int buttonLabel, const LABEL_MASKS &labelMasks)
3086 {
3087   SORT_METHOD_DETAILS sort;
3088   sort.m_sortDescription = sortDescription;
3089   sort.m_buttonLabel = buttonLabel;
3090   sort.m_labelMasks = labelMasks;
3091
3092   m_sortDetails.push_back(sort);
3093 }
3094
3095 void CFileItemList::SetReplaceListing(bool replace)
3096 {
3097   m_replaceListing = replace;
3098 }
3099
3100 void CFileItemList::ClearSortState()
3101 {
3102   m_sortDescription.sortBy = SortByNone;
3103   m_sortDescription.sortOrder = SortOrderNone;
3104   m_sortDescription.sortAttributes = SortAttributeNone;
3105 }
3106
3107 CVideoInfoTag* CFileItem::GetVideoInfoTag()
3108 {
3109   if (!m_videoInfoTag)
3110     m_videoInfoTag = new CVideoInfoTag;
3111
3112   return m_videoInfoTag;
3113 }
3114
3115 CEpgInfoTag* CFileItem::GetEPGInfoTag()
3116 {
3117   if (!m_epgInfoTag)
3118     m_epgInfoTag = new CEpgInfoTag;
3119
3120   return m_epgInfoTag;
3121 }
3122
3123 CPVRChannel* CFileItem::GetPVRChannelInfoTag()
3124 {
3125   if (!m_pvrChannelInfoTag)
3126     m_pvrChannelInfoTag = new CPVRChannel;
3127
3128   return m_pvrChannelInfoTag;
3129 }
3130
3131 CPVRRecording* CFileItem::GetPVRRecordingInfoTag()
3132 {
3133   if (!m_pvrRecordingInfoTag)
3134     m_pvrRecordingInfoTag = new CPVRRecording;
3135
3136   return m_pvrRecordingInfoTag;
3137 }
3138
3139 CPVRTimerInfoTag* CFileItem::GetPVRTimerInfoTag()
3140 {
3141   if (!m_pvrTimerInfoTag)
3142     m_pvrTimerInfoTag = new CPVRTimerInfoTag;
3143
3144   return m_pvrTimerInfoTag;
3145 }
3146
3147 CPictureInfoTag* CFileItem::GetPictureInfoTag()
3148 {
3149   if (!m_pictureInfoTag)
3150     m_pictureInfoTag = new CPictureInfoTag;
3151
3152   return m_pictureInfoTag;
3153 }
3154
3155 MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
3156 {
3157   if (!m_musicInfoTag)
3158     m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
3159
3160   return m_musicInfoTag;
3161 }
3162
3163 std::string CFileItem::FindTrailer() const
3164 {
3165   std::string strFile2;
3166   std::string strFile = m_strPath;
3167   if (IsStack())
3168   {
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));
3178   }
3179   if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
3180   {
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));
3185   }
3186
3187   // no local trailer available for these
3188   if (IsInternetStream()
3189    || URIUtils::IsUPnP(strFile)
3190    || URIUtils::IsBluray(strFile)
3191    || IsLiveTV()
3192    || IsPlugin()
3193    || IsDVD())
3194     return "";
3195
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");
3202
3203   // Precompile our REs
3204   VECCREGEXP matchRegExps;
3205   CRegExp tmpRegExp(true, CRegExp::autoUtf8);
3206   const vector<string>& strMatchRegExps = g_advancedSettings.m_trailerMatchRegExps;
3207
3208   vector<string>::const_iterator strRegExp = strMatchRegExps.begin();
3209   while (strRegExp != strMatchRegExps.end())
3210   {
3211     if (tmpRegExp.RegComp(*strRegExp))
3212     {
3213       matchRegExps.push_back(tmpRegExp);
3214     }
3215     strRegExp++;
3216   }
3217
3218   std::string strTrailer;
3219   for (int i = 0; i < items.Size(); i++)
3220   {
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))
3226     {
3227       strTrailer = items[i]->m_strPath;
3228       break;
3229     }
3230     else
3231     {
3232       VECCREGEXP::iterator expr = matchRegExps.begin();
3233
3234       while (expr != matchRegExps.end())
3235       {
3236         if (expr->RegFind(strCandidate) != -1)
3237         {
3238           strTrailer = items[i]->m_strPath;
3239           i = items.Size();
3240           break;
3241         }
3242         expr++;
3243       }
3244     }
3245   }
3246
3247   return strTrailer;
3248 }
3249
3250 int CFileItem::GetVideoContentType() const
3251 {
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;
3259
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;
3265
3266   return type;
3267 }
3268
3269 bool CFileItem::IsResumePointSet() const
3270 {
3271   return (HasVideoInfoTag() && GetVideoInfoTag()->m_resumePoint.IsSet()) ||
3272       (HasPVRRecordingInfoTag() && GetPVRRecordingInfoTag()->GetLastPlayedPosition() > 0);
3273 }
3274
3275 double CFileItem::GetCurrentResumeTime() const
3276 {
3277   if (HasPVRRecordingInfoTag())
3278   {
3279     // This will retrieve 'fresh' resume information from the PVR server
3280     int rc = GetPVRRecordingInfoTag()->GetLastPlayedPosition();
3281     if (rc > 0)
3282       return rc;
3283     // Fall through to default value
3284   }
3285   if (HasVideoInfoTag() && GetVideoInfoTag()->m_resumePoint.IsSet())
3286   {
3287     return GetVideoInfoTag()->m_resumePoint.timeInSeconds;
3288   }
3289   // Resume from start when resume points are invalid or the PVR server returns an error
3290   return 0;
3291 }