PageRenderTime 70ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/xbmc/FileItem.cpp

https://github.com/weitao2012/android-1
C++ | 2977 lines | 2533 code | 313 blank | 131 comment | 454 complexity | 39426c571bec4e4c90eb0b8fca756f38 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. /*
  2. * Copyright (C) 2005-2008 Team XBMC
  3. * http://www.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, write to
  17. * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18. * http://www.gnu.org/copyleft/gpl.html
  19. *
  20. */
  21. #include "FileItem.h"
  22. #include "guilib/LocalizeStrings.h"
  23. #include "utils/StringUtils.h"
  24. #include "utils/URIUtils.h"
  25. #include "Util.h"
  26. #include "playlists/PlayListFactory.h"
  27. #include "utils/Crc32.h"
  28. #include "filesystem/Directory.h"
  29. #include "filesystem/StackDirectory.h"
  30. #include "filesystem/CurlFile.h"
  31. #include "filesystem/MultiPathDirectory.h"
  32. #include "filesystem/MusicDatabaseDirectory.h"
  33. #include "filesystem/VideoDatabaseDirectory.h"
  34. #include "music/tags/MusicInfoTagLoaderFactory.h"
  35. #include "CueDocument.h"
  36. #include "video/VideoDatabase.h"
  37. #include "music/MusicDatabase.h"
  38. #include "utils/TuxBoxUtil.h"
  39. #include "video/VideoInfoTag.h"
  40. #include "threads/SingleLock.h"
  41. #include "music/tags/MusicInfoTag.h"
  42. #include "pictures/PictureInfoTag.h"
  43. #include "music/Artist.h"
  44. #include "music/Album.h"
  45. #include "music/Song.h"
  46. #include "URL.h"
  47. #include "settings/GUISettings.h"
  48. #include "settings/AdvancedSettings.h"
  49. #include "settings/Settings.h"
  50. #include "utils/RegExp.h"
  51. #include "utils/log.h"
  52. #include "utils/Variant.h"
  53. #include "music/karaoke/karaokelyricsfactory.h"
  54. #include "utils/Mime.h"
  55. using namespace std;
  56. using namespace XFILE;
  57. using namespace PLAYLIST;
  58. using namespace MUSIC_INFO;
  59. CFileItem::CFileItem(const CSong& song)
  60. {
  61. m_musicInfoTag = NULL;
  62. m_videoInfoTag = NULL;
  63. m_pictureInfoTag = NULL;
  64. Reset();
  65. SetLabel(song.strTitle);
  66. m_strPath = song.strFileName;
  67. GetMusicInfoTag()->SetSong(song);
  68. m_lStartOffset = song.iStartOffset;
  69. m_lStartPartNumber = 0;
  70. SetProperty("item_start", song.iStartOffset);
  71. m_lEndOffset = song.iEndOffset;
  72. m_strThumbnailImage = song.strThumb;
  73. }
  74. CFileItem::CFileItem(const CStdString &path, const CAlbum& album)
  75. {
  76. m_musicInfoTag = NULL;
  77. m_videoInfoTag = NULL;
  78. m_pictureInfoTag = NULL;
  79. Reset();
  80. SetLabel(album.strAlbum);
  81. m_strPath = path;
  82. m_bIsFolder = true;
  83. m_strLabel2 = StringUtils::Join(album.artist, g_advancedSettings.m_musicItemSeparator);
  84. URIUtils::AddSlashAtEnd(m_strPath);
  85. GetMusicInfoTag()->SetAlbum(album);
  86. m_bIsAlbum = true;
  87. CMusicDatabase::SetPropertiesFromAlbum(*this,album);
  88. }
  89. CFileItem::CFileItem(const CMusicInfoTag& music)
  90. {
  91. m_musicInfoTag = NULL;
  92. m_videoInfoTag = NULL;
  93. m_pictureInfoTag = NULL;
  94. Reset();
  95. SetLabel(music.GetTitle());
  96. m_strPath = music.GetURL();
  97. m_bIsFolder = URIUtils::HasSlashAtEnd(m_strPath);
  98. *GetMusicInfoTag() = music;
  99. FillInDefaultIcon();
  100. }
  101. CFileItem::CFileItem(const CVideoInfoTag& movie)
  102. {
  103. m_musicInfoTag = NULL;
  104. m_videoInfoTag = NULL;
  105. m_pictureInfoTag = NULL;
  106. Reset();
  107. SetLabel(movie.m_strTitle);
  108. if (movie.m_strFileNameAndPath.IsEmpty())
  109. {
  110. m_strPath = movie.m_strPath;
  111. URIUtils::AddSlashAtEnd(m_strPath);
  112. m_bIsFolder = true;
  113. }
  114. else
  115. {
  116. m_strPath = movie.m_strFileNameAndPath;
  117. m_bIsFolder = false;
  118. }
  119. *GetVideoInfoTag() = movie;
  120. if (movie.m_iSeason == 0) SetProperty("isspecial", "true");
  121. FillInDefaultIcon();
  122. }
  123. CFileItem::CFileItem(const CArtist& artist)
  124. {
  125. m_musicInfoTag = NULL;
  126. m_videoInfoTag = NULL;
  127. m_pictureInfoTag = NULL;
  128. Reset();
  129. SetLabel(artist.strArtist);
  130. m_strPath = artist.strArtist;
  131. m_bIsFolder = true;
  132. URIUtils::AddSlashAtEnd(m_strPath);
  133. GetMusicInfoTag()->SetArtist(artist.strArtist);
  134. }
  135. CFileItem::CFileItem(const CGenre& genre)
  136. {
  137. m_musicInfoTag = NULL;
  138. m_videoInfoTag = NULL;
  139. m_pictureInfoTag = NULL;
  140. Reset();
  141. SetLabel(genre.strGenre);
  142. m_strPath = genre.strGenre;
  143. m_bIsFolder = true;
  144. URIUtils::AddSlashAtEnd(m_strPath);
  145. GetMusicInfoTag()->SetGenre(genre.strGenre);
  146. }
  147. CFileItem::CFileItem(const CFileItem& item): CGUIListItem()
  148. {
  149. m_musicInfoTag = NULL;
  150. m_videoInfoTag = NULL;
  151. m_pictureInfoTag = NULL;
  152. *this = item;
  153. }
  154. CFileItem::CFileItem(const CGUIListItem& item)
  155. {
  156. m_musicInfoTag = NULL;
  157. m_videoInfoTag = NULL;
  158. m_pictureInfoTag = NULL;
  159. Reset();
  160. // not particularly pretty, but it gets around the issue of Reset() defaulting
  161. // parameters in the CGUIListItem base class.
  162. *((CGUIListItem *)this) = item;
  163. }
  164. CFileItem::CFileItem(void)
  165. {
  166. m_musicInfoTag = NULL;
  167. m_videoInfoTag = NULL;
  168. m_pictureInfoTag = NULL;
  169. Reset();
  170. }
  171. CFileItem::CFileItem(const CStdString& strLabel)
  172. : CGUIListItem()
  173. {
  174. m_musicInfoTag = NULL;
  175. m_videoInfoTag = NULL;
  176. m_pictureInfoTag = NULL;
  177. Reset();
  178. SetLabel(strLabel);
  179. }
  180. CFileItem::CFileItem(const CStdString& strPath, bool bIsFolder)
  181. {
  182. m_musicInfoTag = NULL;
  183. m_videoInfoTag = NULL;
  184. m_pictureInfoTag = NULL;
  185. Reset();
  186. m_strPath = strPath;
  187. m_bIsFolder = bIsFolder;
  188. // tuxbox urls cannot have a / at end
  189. if (m_bIsFolder && !m_strPath.IsEmpty() && !IsFileFolder() && !URIUtils::IsTuxBox(m_strPath))
  190. URIUtils::AddSlashAtEnd(m_strPath);
  191. }
  192. CFileItem::CFileItem(const CMediaSource& share)
  193. {
  194. m_musicInfoTag = NULL;
  195. m_videoInfoTag = NULL;
  196. m_pictureInfoTag = NULL;
  197. Reset();
  198. m_bIsFolder = true;
  199. m_bIsShareOrDrive = true;
  200. m_strPath = share.strPath;
  201. URIUtils::AddSlashAtEnd(m_strPath);
  202. CStdString label = share.strName;
  203. if (!share.strStatus.IsEmpty())
  204. label.Format("%s (%s)", share.strName.c_str(), share.strStatus.c_str());
  205. SetLabel(label);
  206. m_iLockMode = share.m_iLockMode;
  207. m_strLockCode = share.m_strLockCode;
  208. m_iHasLock = share.m_iHasLock;
  209. m_iBadPwdCount = share.m_iBadPwdCount;
  210. m_iDriveType = share.m_iDriveType;
  211. m_strThumbnailImage = share.m_strThumbnailImage;
  212. SetLabelPreformated(true);
  213. if (IsDVD())
  214. GetVideoInfoTag()->m_strFileNameAndPath = share.strDiskUniqueId; // share.strDiskUniqueId contains disc unique id
  215. }
  216. CFileItem::~CFileItem(void)
  217. {
  218. delete m_musicInfoTag;
  219. delete m_videoInfoTag;
  220. delete m_pictureInfoTag;
  221. m_musicInfoTag = NULL;
  222. m_videoInfoTag = NULL;
  223. m_pictureInfoTag = NULL;
  224. }
  225. const CFileItem& CFileItem::operator=(const CFileItem& item)
  226. {
  227. if (this == &item) return * this;
  228. CGUIListItem::operator=(item);
  229. m_bLabelPreformated=item.m_bLabelPreformated;
  230. FreeMemory();
  231. m_strPath = item.GetPath();
  232. m_bIsParentFolder = item.m_bIsParentFolder;
  233. m_iDriveType = item.m_iDriveType;
  234. m_bIsShareOrDrive = item.m_bIsShareOrDrive;
  235. m_dateTime = item.m_dateTime;
  236. m_dwSize = item.m_dwSize;
  237. if (item.HasMusicInfoTag())
  238. {
  239. m_musicInfoTag = GetMusicInfoTag();
  240. if (m_musicInfoTag)
  241. *m_musicInfoTag = *item.m_musicInfoTag;
  242. }
  243. else
  244. {
  245. delete m_musicInfoTag;
  246. m_musicInfoTag = NULL;
  247. }
  248. if (item.HasVideoInfoTag())
  249. {
  250. m_videoInfoTag = GetVideoInfoTag();
  251. if (m_videoInfoTag)
  252. *m_videoInfoTag = *item.m_videoInfoTag;
  253. }
  254. else
  255. {
  256. delete m_videoInfoTag;
  257. m_videoInfoTag = NULL;
  258. }
  259. if (item.HasPictureInfoTag())
  260. {
  261. m_pictureInfoTag = GetPictureInfoTag();
  262. if (m_pictureInfoTag)
  263. *m_pictureInfoTag = *item.m_pictureInfoTag;
  264. }
  265. else
  266. {
  267. delete m_pictureInfoTag;
  268. m_pictureInfoTag = NULL;
  269. }
  270. m_lStartOffset = item.m_lStartOffset;
  271. m_lStartPartNumber = item.m_lStartPartNumber;
  272. m_lEndOffset = item.m_lEndOffset;
  273. m_strDVDLabel = item.m_strDVDLabel;
  274. m_strTitle = item.m_strTitle;
  275. m_iprogramCount = item.m_iprogramCount;
  276. m_idepth = item.m_idepth;
  277. m_iLockMode = item.m_iLockMode;
  278. m_strLockCode = item.m_strLockCode;
  279. m_iHasLock = item.m_iHasLock;
  280. m_iBadPwdCount = item.m_iBadPwdCount;
  281. m_bCanQueue=item.m_bCanQueue;
  282. m_mimetype = item.m_mimetype;
  283. m_extrainfo = item.m_extrainfo;
  284. m_specialSort = item.m_specialSort;
  285. m_bIsAlbum = item.m_bIsAlbum;
  286. return *this;
  287. }
  288. void CFileItem::Reset()
  289. {
  290. m_strLabel2.Empty();
  291. SetLabel("");
  292. m_bLabelPreformated=false;
  293. FreeIcons();
  294. m_overlayIcon = ICON_OVERLAY_NONE;
  295. m_bSelected = false;
  296. m_bIsAlbum = false;
  297. m_strDVDLabel.Empty();
  298. m_strTitle.Empty();
  299. m_strPath.Empty();
  300. m_dwSize = 0;
  301. m_bIsFolder = false;
  302. m_bIsParentFolder=false;
  303. m_bIsShareOrDrive = false;
  304. m_dateTime.Reset();
  305. m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
  306. m_lStartOffset = 0;
  307. m_lStartPartNumber = 0;
  308. m_lEndOffset = 0;
  309. m_iprogramCount = 0;
  310. m_idepth = 1;
  311. m_iLockMode = LOCK_MODE_EVERYONE;
  312. m_strLockCode = "";
  313. m_iBadPwdCount = 0;
  314. m_iHasLock = 0;
  315. m_bCanQueue=true;
  316. m_mimetype = "";
  317. delete m_musicInfoTag;
  318. m_musicInfoTag=NULL;
  319. delete m_videoInfoTag;
  320. m_videoInfoTag=NULL;
  321. delete m_pictureInfoTag;
  322. m_pictureInfoTag=NULL;
  323. m_extrainfo.Empty();
  324. m_specialSort = SortSpecialNone;
  325. SetInvalid();
  326. }
  327. void CFileItem::Archive(CArchive& ar)
  328. {
  329. CGUIListItem::Archive(ar);
  330. if (ar.IsStoring())
  331. {
  332. ar << m_bIsParentFolder;
  333. ar << m_bLabelPreformated;
  334. ar << m_strPath;
  335. ar << m_bIsShareOrDrive;
  336. ar << m_iDriveType;
  337. ar << m_dateTime;
  338. ar << m_dwSize;
  339. ar << m_strDVDLabel;
  340. ar << m_strTitle;
  341. ar << m_iprogramCount;
  342. ar << m_idepth;
  343. ar << m_lStartOffset;
  344. ar << m_lStartPartNumber;
  345. ar << m_lEndOffset;
  346. ar << m_iLockMode;
  347. ar << m_strLockCode;
  348. ar << m_iBadPwdCount;
  349. ar << m_bCanQueue;
  350. ar << m_mimetype;
  351. ar << m_extrainfo;
  352. ar << m_specialSort;
  353. if (m_musicInfoTag)
  354. {
  355. ar << 1;
  356. ar << *m_musicInfoTag;
  357. }
  358. else
  359. ar << 0;
  360. if (m_videoInfoTag)
  361. {
  362. ar << 1;
  363. ar << *m_videoInfoTag;
  364. }
  365. else
  366. ar << 0;
  367. if (m_pictureInfoTag)
  368. {
  369. ar << 1;
  370. ar << *m_pictureInfoTag;
  371. }
  372. else
  373. ar << 0;
  374. }
  375. else
  376. {
  377. ar >> m_bIsParentFolder;
  378. ar >> m_bLabelPreformated;
  379. ar >> m_strPath;
  380. ar >> m_bIsShareOrDrive;
  381. ar >> m_iDriveType;
  382. ar >> m_dateTime;
  383. ar >> m_dwSize;
  384. ar >> m_strDVDLabel;
  385. ar >> m_strTitle;
  386. ar >> m_iprogramCount;
  387. ar >> m_idepth;
  388. ar >> m_lStartOffset;
  389. ar >> m_lStartPartNumber;
  390. ar >> m_lEndOffset;
  391. int temp;
  392. ar >> temp;
  393. m_iLockMode = (LockType)temp;
  394. ar >> m_strLockCode;
  395. ar >> m_iBadPwdCount;
  396. ar >> m_bCanQueue;
  397. ar >> m_mimetype;
  398. ar >> m_extrainfo;
  399. ar >> temp;
  400. m_specialSort = (SortSpecial)temp;
  401. int iType;
  402. ar >> iType;
  403. if (iType == 1)
  404. ar >> *GetMusicInfoTag();
  405. ar >> iType;
  406. if (iType == 1)
  407. ar >> *GetVideoInfoTag();
  408. ar >> iType;
  409. if (iType == 1)
  410. ar >> *GetPictureInfoTag();
  411. SetInvalid();
  412. }
  413. }
  414. void CFileItem::Serialize(CVariant& value)
  415. {
  416. //CGUIListItem::Serialize(value["CGUIListItem"]);
  417. value["strPath"] = m_strPath;
  418. value["dateTime"] = (m_dateTime.IsValid()) ? m_dateTime.GetAsRFC1123DateTime() : "";
  419. value["size"] = (int) m_dwSize / 1000;
  420. value["DVDLabel"] = m_strDVDLabel;
  421. value["title"] = m_strTitle;
  422. value["mimetype"] = GetMimeType();
  423. value["extrainfo"] = m_extrainfo;
  424. if (m_musicInfoTag)
  425. (*m_musicInfoTag).Serialize(value["musicInfoTag"]);
  426. if (m_videoInfoTag)
  427. (*m_videoInfoTag).Serialize(value["videoInfoTag"]);
  428. if (m_pictureInfoTag)
  429. (*m_pictureInfoTag).Serialize(value["pictureInfoTag"]);
  430. }
  431. void CFileItem::ToSortable(SortItem &sortable)
  432. {
  433. sortable[FieldPath] = m_strPath;
  434. sortable[FieldDate] = (m_dateTime.IsValid()) ? m_dateTime.GetAsDBDateTime() : "";
  435. sortable[FieldSize] = m_dwSize;
  436. sortable[FieldDriveType] = m_iDriveType;
  437. sortable[FieldStartOffset] = m_lStartOffset;
  438. sortable[FieldStartOffset] = m_lEndOffset;
  439. sortable[FieldProgramCount] = m_iprogramCount;
  440. sortable[FieldBitrate] = m_dwSize;
  441. sortable[FieldTitle] = m_strTitle;
  442. sortable[FieldSortSpecial] = m_specialSort;
  443. sortable[FieldFolder] = m_bIsFolder;
  444. // If there's ever a need to convert more properties from CGUIListItem it might be
  445. // worth to make CGUIListItem implement ISortable as well and call it from here
  446. sortable[FieldLabel] = GetLabel();
  447. if (HasMusicInfoTag())
  448. GetMusicInfoTag()->ToSortable(sortable);
  449. if (HasVideoInfoTag())
  450. GetVideoInfoTag()->ToSortable(sortable);
  451. if (HasPictureInfoTag())
  452. GetPictureInfoTag()->ToSortable(sortable);
  453. }
  454. bool CFileItem::Exists(bool bUseCache /* = true */) const
  455. {
  456. if (m_strPath.IsEmpty()
  457. || m_strPath.Equals("add")
  458. || IsInternetStream()
  459. || IsParentFolder()
  460. || IsVirtualDirectoryRoot()
  461. || IsPlugin())
  462. return true;
  463. if (IsVideoDb() && HasVideoInfoTag())
  464. {
  465. CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
  466. return dbItem.Exists();
  467. }
  468. CStdString strPath = m_strPath;
  469. if (URIUtils::IsMultiPath(strPath))
  470. strPath = CMultiPathDirectory::GetFirstPath(strPath);
  471. if (URIUtils::IsStack(strPath))
  472. strPath = CStackDirectory::GetFirstStackedFile(strPath);
  473. if (m_bIsFolder)
  474. return CDirectory::Exists(strPath);
  475. else
  476. return CFile::Exists(strPath, bUseCache);
  477. return false;
  478. }
  479. bool CFileItem::IsVideo() const
  480. {
  481. /* check preset mime type */
  482. if( m_mimetype.Left(6).Equals("video/") )
  483. return true;
  484. if (HasVideoInfoTag()) return true;
  485. if (HasMusicInfoTag()) return false;
  486. if (HasPictureInfoTag()) return false;
  487. if (IsHDHomeRun() || IsTuxBox() || URIUtils::IsDVD(m_strPath) || IsSlingbox())
  488. return true;
  489. CStdString extension;
  490. if( m_mimetype.Left(12).Equals("application/") )
  491. { /* check for some standard types */
  492. extension = m_mimetype.Mid(12);
  493. if( extension.Equals("ogg")
  494. || extension.Equals("mp4")
  495. || extension.Equals("mxf") )
  496. return true;
  497. }
  498. URIUtils::GetExtension(m_strPath, extension);
  499. if (extension.IsEmpty())
  500. return false;
  501. extension.ToLower();
  502. return (g_settings.m_videoExtensions.Find(extension) != -1);
  503. }
  504. bool CFileItem::IsDiscStub() const
  505. {
  506. if (IsVideoDb() && HasVideoInfoTag())
  507. {
  508. CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
  509. return dbItem.IsDiscStub();
  510. }
  511. CStdString strExtension;
  512. URIUtils::GetExtension(m_strPath, strExtension);
  513. if (strExtension.IsEmpty())
  514. return false;
  515. strExtension.ToLower();
  516. strExtension += '|';
  517. return (g_settings.m_discStubExtensions + '|').Find(strExtension) != -1;
  518. }
  519. bool CFileItem::IsAudio() const
  520. {
  521. /* check preset mime type */
  522. if( m_mimetype.Left(6).Equals("audio/") )
  523. return true;
  524. if (HasMusicInfoTag()) return true;
  525. if (HasVideoInfoTag()) return false;
  526. if (HasPictureInfoTag()) return false;
  527. if (IsCDDA()) return true;
  528. if (!m_bIsFolder && IsLastFM()) return true;
  529. CStdString extension;
  530. if( m_mimetype.Left(12).Equals("application/") )
  531. { /* check for some standard types */
  532. extension = m_mimetype.Mid(12);
  533. if( extension.Equals("ogg")
  534. || extension.Equals("mp4")
  535. || extension.Equals("mxf") )
  536. return true;
  537. }
  538. URIUtils::GetExtension(m_strPath, extension);
  539. if (extension.IsEmpty())
  540. return false;
  541. extension.ToLower();
  542. return (g_settings.m_musicExtensions.Find(extension) != -1);
  543. }
  544. bool CFileItem::IsKaraoke() const
  545. {
  546. if ( !IsAudio() || IsLastFM())
  547. return false;
  548. return CKaraokeLyricsFactory::HasLyrics( m_strPath );
  549. }
  550. bool CFileItem::IsPicture() const
  551. {
  552. if( m_mimetype.Left(6).Equals("image/") )
  553. return true;
  554. if (HasPictureInfoTag()) return true;
  555. if (HasMusicInfoTag()) return false;
  556. if (HasVideoInfoTag()) return false;
  557. return CUtil::IsPicture(m_strPath);
  558. }
  559. bool CFileItem::IsLyrics() const
  560. {
  561. return URIUtils::GetExtension(m_strPath).Equals(".cdg", false) || URIUtils::GetExtension(m_strPath).Equals(".lrc", false);
  562. }
  563. bool CFileItem::IsCUESheet() const
  564. {
  565. return URIUtils::GetExtension(m_strPath).Equals(".cue", false);
  566. }
  567. bool CFileItem::IsLastFM() const
  568. {
  569. return URIUtils::IsLastFM(m_strPath);
  570. }
  571. bool CFileItem::IsInternetStream(const bool bStrictCheck /* = false */) const
  572. {
  573. if (HasProperty("IsHTTPDirectory"))
  574. return false;
  575. return URIUtils::IsInternetStream(m_strPath, bStrictCheck);
  576. }
  577. bool CFileItem::IsFileFolder() const
  578. {
  579. return (
  580. IsSmartPlayList() ||
  581. (IsPlayList() && g_advancedSettings.m_playlistAsFolders) ||
  582. IsAPK() ||
  583. IsZIP() ||
  584. IsRAR() ||
  585. IsRSS() ||
  586. IsType(".ogg") ||
  587. IsType(".nsf") ||
  588. IsType(".sid") ||
  589. IsType(".sap")
  590. );
  591. }
  592. bool CFileItem::IsSmartPlayList() const
  593. {
  594. CStdString strExtension;
  595. URIUtils::GetExtension(m_strPath, strExtension);
  596. strExtension.ToLower();
  597. return (strExtension == ".xsp");
  598. }
  599. bool CFileItem::IsPlayList() const
  600. {
  601. return CPlayListFactory::IsPlaylist(*this);
  602. }
  603. bool CFileItem::IsPythonScript() const
  604. {
  605. return URIUtils::GetExtension(m_strPath).Equals(".py", false);
  606. }
  607. bool CFileItem::IsType(const char *ext) const
  608. {
  609. return URIUtils::GetExtension(m_strPath).Equals(ext, false);
  610. }
  611. bool CFileItem::IsNFO() const
  612. {
  613. return URIUtils::GetExtension(m_strPath).Equals(".nfo", false);
  614. }
  615. bool CFileItem::IsDVDImage() const
  616. {
  617. CStdString strExtension;
  618. URIUtils::GetExtension(m_strPath, strExtension);
  619. return (strExtension.Equals(".img") || strExtension.Equals(".iso") || strExtension.Equals(".nrg"));
  620. }
  621. bool CFileItem::IsOpticalMediaFile() const
  622. {
  623. bool found = IsDVDFile(false, true);
  624. if (found)
  625. return true;
  626. return IsBDFile();
  627. }
  628. bool CFileItem::IsDVDFile(bool bVobs /*= true*/, bool bIfos /*= true*/) const
  629. {
  630. CStdString strFileName = URIUtils::GetFileName(m_strPath);
  631. if (bIfos)
  632. {
  633. if (strFileName.Equals("video_ts.ifo")) return true;
  634. if (strFileName.Left(4).Equals("vts_") && strFileName.Right(6).Equals("_0.ifo") && strFileName.length() == 12) return true;
  635. }
  636. if (bVobs)
  637. {
  638. if (strFileName.Equals("video_ts.vob")) return true;
  639. if (strFileName.Left(4).Equals("vts_") && strFileName.Right(4).Equals(".vob")) return true;
  640. }
  641. return false;
  642. }
  643. bool CFileItem::IsBDFile() const
  644. {
  645. CStdString strFileName = URIUtils::GetFileName(m_strPath);
  646. return (strFileName.Equals("index.bdmv"));
  647. }
  648. bool CFileItem::IsRAR() const
  649. {
  650. return URIUtils::IsRAR(m_strPath);
  651. }
  652. bool CFileItem::IsAPK() const
  653. {
  654. return URIUtils::IsAPK(m_strPath);
  655. }
  656. bool CFileItem::IsZIP() const
  657. {
  658. return URIUtils::IsZIP(m_strPath);
  659. }
  660. bool CFileItem::IsCBZ() const
  661. {
  662. return URIUtils::GetExtension(m_strPath).Equals(".cbz", false);
  663. }
  664. bool CFileItem::IsCBR() const
  665. {
  666. return URIUtils::GetExtension(m_strPath).Equals(".cbr", false);
  667. }
  668. bool CFileItem::IsRSS() const
  669. {
  670. if (m_strPath.Left(6).Equals("rss://"))
  671. return true;
  672. return URIUtils::GetExtension(m_strPath).Equals(".rss")
  673. || GetMimeType() == "application/rss+xml";
  674. }
  675. bool CFileItem::IsAndroidApp() const
  676. {
  677. return URIUtils::IsAndroidApp(m_strPath);
  678. }
  679. bool CFileItem::IsStack() const
  680. {
  681. return URIUtils::IsStack(m_strPath);
  682. }
  683. bool CFileItem::IsPlugin() const
  684. {
  685. return URIUtils::IsPlugin(m_strPath);
  686. }
  687. bool CFileItem::IsScript() const
  688. {
  689. return URIUtils::IsScript(m_strPath);
  690. }
  691. bool CFileItem::IsAddonsPath() const
  692. {
  693. return URIUtils::IsAddonsPath(m_strPath);
  694. }
  695. bool CFileItem::IsSourcesPath() const
  696. {
  697. return URIUtils::IsSourcesPath(m_strPath);
  698. }
  699. bool CFileItem::IsMultiPath() const
  700. {
  701. return URIUtils::IsMultiPath(m_strPath);
  702. }
  703. bool CFileItem::IsCDDA() const
  704. {
  705. return URIUtils::IsCDDA(m_strPath);
  706. }
  707. bool CFileItem::IsDVD() const
  708. {
  709. return URIUtils::IsDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
  710. }
  711. bool CFileItem::IsOnDVD() const
  712. {
  713. return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
  714. }
  715. bool CFileItem::IsNfs() const
  716. {
  717. return URIUtils::IsNfs(m_strPath);
  718. }
  719. bool CFileItem::IsAfp() const
  720. {
  721. return URIUtils::IsAfp(m_strPath);
  722. }
  723. bool CFileItem::IsOnLAN() const
  724. {
  725. return URIUtils::IsOnLAN(m_strPath);
  726. }
  727. bool CFileItem::IsISO9660() const
  728. {
  729. return URIUtils::IsISO9660(m_strPath);
  730. }
  731. bool CFileItem::IsRemote() const
  732. {
  733. return URIUtils::IsRemote(m_strPath);
  734. }
  735. bool CFileItem::IsSmb() const
  736. {
  737. return URIUtils::IsSmb(m_strPath);
  738. }
  739. bool CFileItem::IsURL() const
  740. {
  741. return URIUtils::IsURL(m_strPath);
  742. }
  743. bool CFileItem::IsDAAP() const
  744. {
  745. return URIUtils::IsDAAP(m_strPath);
  746. }
  747. bool CFileItem::IsTuxBox() const
  748. {
  749. return URIUtils::IsTuxBox(m_strPath);
  750. }
  751. bool CFileItem::IsMythTV() const
  752. {
  753. return URIUtils::IsMythTV(m_strPath);
  754. }
  755. bool CFileItem::IsHDHomeRun() const
  756. {
  757. return URIUtils::IsHDHomeRun(m_strPath);
  758. }
  759. bool CFileItem::IsSlingbox() const
  760. {
  761. return URIUtils::IsSlingbox(m_strPath);
  762. }
  763. bool CFileItem::IsVTP() const
  764. {
  765. return URIUtils::IsVTP(m_strPath);
  766. }
  767. bool CFileItem::IsLiveTV() const
  768. {
  769. return URIUtils::IsLiveTV(m_strPath);
  770. }
  771. bool CFileItem::IsHD() const
  772. {
  773. return URIUtils::IsHD(m_strPath);
  774. }
  775. bool CFileItem::IsMusicDb() const
  776. {
  777. CURL url(m_strPath);
  778. return url.GetProtocol().Equals("musicdb");
  779. }
  780. bool CFileItem::IsVideoDb() const
  781. {
  782. CURL url(m_strPath);
  783. return url.GetProtocol().Equals("videodb");
  784. }
  785. bool CFileItem::IsVirtualDirectoryRoot() const
  786. {
  787. return (m_bIsFolder && m_strPath.IsEmpty());
  788. }
  789. bool CFileItem::IsRemovable() const
  790. {
  791. return IsOnDVD() || IsCDDA() || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE;
  792. }
  793. bool CFileItem::IsReadOnly() const
  794. {
  795. if (IsParentFolder()) return true;
  796. if (m_bIsShareOrDrive) return true;
  797. return !CUtil::SupportsFileOperations(m_strPath);
  798. }
  799. void CFileItem::FillInDefaultIcon()
  800. {
  801. //CLog::Log(LOGINFO, "FillInDefaultIcon(%s)", pItem->GetLabel().c_str());
  802. // find the default icon for a file or folder item
  803. // for files this can be the (depending on the file type)
  804. // default picture for photo's
  805. // default picture for songs
  806. // default picture for videos
  807. // default picture for shortcuts
  808. // default picture for playlists
  809. // or the icon embedded in an .xbe
  810. //
  811. // for folders
  812. // for .. folders the default picture for parent folder
  813. // for other folders the defaultFolder.png
  814. if (GetIconImage().IsEmpty())
  815. {
  816. if (!m_bIsFolder)
  817. {
  818. /* To reduce the average runtime of this code, this list should
  819. * be ordered with most frequently seen types first. Also bear
  820. * in mind the complexity of the code behind the check in the
  821. * case of IsWhatater() returns false.
  822. */
  823. if ( IsAudio() )
  824. {
  825. // audio
  826. SetIconImage("DefaultAudio.png");
  827. }
  828. else if ( IsVideo() )
  829. {
  830. // video
  831. SetIconImage("DefaultVideo.png");
  832. }
  833. else if ( IsPicture() )
  834. {
  835. // picture
  836. SetIconImage("DefaultPicture.png");
  837. }
  838. else if ( IsPlayList() )
  839. {
  840. SetIconImage("DefaultPlaylist.png");
  841. }
  842. else if ( IsPythonScript() )
  843. {
  844. SetIconImage("DefaultScript.png");
  845. }
  846. else
  847. {
  848. // default icon for unknown file type
  849. SetIconImage("DefaultFile.png");
  850. }
  851. }
  852. else
  853. {
  854. if ( IsPlayList() )
  855. {
  856. SetIconImage("DefaultPlaylist.png");
  857. }
  858. else if (IsParentFolder())
  859. {
  860. SetIconImage("DefaultFolderBack.png");
  861. }
  862. else
  863. {
  864. SetIconImage("DefaultFolder.png");
  865. }
  866. }
  867. }
  868. // Set the icon overlays (if applicable)
  869. if (!HasOverlay())
  870. {
  871. if (URIUtils::IsInRAR(m_strPath))
  872. SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR);
  873. else if (URIUtils::IsInZIP(m_strPath))
  874. SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP);
  875. }
  876. }
  877. void CFileItem::RemoveExtension()
  878. {
  879. if (m_bIsFolder)
  880. return;
  881. CStdString strLabel = GetLabel();
  882. URIUtils::RemoveExtension(strLabel);
  883. SetLabel(strLabel);
  884. }
  885. void CFileItem::CleanString()
  886. {
  887. if (IsLiveTV())
  888. return;
  889. CStdString strLabel = GetLabel();
  890. CStdString strTitle, strTitleAndYear, strYear;
  891. CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, true );
  892. SetLabel(strTitleAndYear);
  893. }
  894. void CFileItem::SetLabel(const CStdString &strLabel)
  895. {
  896. if (strLabel=="..")
  897. {
  898. m_bIsParentFolder=true;
  899. m_bIsFolder=true;
  900. m_specialSort = SortSpecialOnTop;
  901. SetLabelPreformated(true);
  902. }
  903. CGUIListItem::SetLabel(strLabel);
  904. }
  905. void CFileItem::SetFileSizeLabel()
  906. {
  907. if( m_bIsFolder && m_dwSize == 0 )
  908. SetLabel2("");
  909. else
  910. SetLabel2(StringUtils::SizeToString(m_dwSize));
  911. }
  912. CURL CFileItem::GetAsUrl() const
  913. {
  914. return CURL(m_strPath);
  915. }
  916. bool CFileItem::CanQueue() const
  917. {
  918. return m_bCanQueue;
  919. }
  920. void CFileItem::SetCanQueue(bool bYesNo)
  921. {
  922. m_bCanQueue=bYesNo;
  923. }
  924. bool CFileItem::IsParentFolder() const
  925. {
  926. return m_bIsParentFolder;
  927. }
  928. const CStdString& CFileItem::GetMimeType(bool lookup /*= true*/) const
  929. {
  930. if( m_mimetype.IsEmpty() && lookup)
  931. {
  932. // discard const qualifyier
  933. CStdString& m_ref = (CStdString&)m_mimetype;
  934. if( m_bIsFolder )
  935. m_ref = "x-directory/normal";
  936. else if( m_strPath.Left(8).Equals("shout://")
  937. || m_strPath.Left(7).Equals("http://")
  938. || m_strPath.Left(8).Equals("https://"))
  939. {
  940. CCurlFile::GetMimeType(GetAsUrl(), m_ref);
  941. // try to get mime-type again but with an NSPlayer User-Agent
  942. // in order for server to provide correct mime-type. Allows us
  943. // to properly detect an MMS stream
  944. if (m_ref.Left(11).Equals("video/x-ms-"))
  945. CCurlFile::GetMimeType(GetAsUrl(), m_ref, "NSPlayer/11.00.6001.7000");
  946. // make sure there are no options set in mime-type
  947. // mime-type can look like "video/x-ms-asf ; charset=utf8"
  948. int i = m_ref.Find(';');
  949. if(i>=0)
  950. m_ref.Delete(i,m_ref.length()-i);
  951. m_ref.Trim();
  952. }
  953. else
  954. m_ref = CMime::GetMimeType(*this);
  955. // if it's still empty set to an unknown type
  956. if( m_ref.IsEmpty() )
  957. m_ref = "application/octet-stream";
  958. }
  959. // change protocol to mms for the following mome-type. Allows us to create proper FileMMS.
  960. if( m_mimetype.Left(32).Equals("application/vnd.ms.wms-hdr.asfv1") || m_mimetype.Left(24).Equals("application/x-mms-framed") )
  961. {
  962. CStdString& m_path = (CStdString&)m_strPath;
  963. m_path.Replace("http:", "mms:");
  964. }
  965. return m_mimetype;
  966. }
  967. bool CFileItem::IsSamePath(const CFileItem *item) const
  968. {
  969. if (!item)
  970. return false;
  971. if (item->GetPath() == m_strPath)
  972. {
  973. if (item->HasProperty("item_start") || HasProperty("item_start"))
  974. return (item->GetProperty("item_start") == GetProperty("item_start"));
  975. return true;
  976. }
  977. if (IsMusicDb() && HasMusicInfoTag())
  978. {
  979. CFileItem dbItem(m_musicInfoTag->GetURL(), false);
  980. dbItem.SetProperty("item_start", GetProperty("item_start"));
  981. return dbItem.IsSamePath(item);
  982. }
  983. if (IsVideoDb() && HasVideoInfoTag())
  984. {
  985. CFileItem dbItem(m_videoInfoTag->m_strFileNameAndPath, false);
  986. dbItem.SetProperty("item_start", GetProperty("item_start"));
  987. return dbItem.IsSamePath(item);
  988. }
  989. if (item->IsMusicDb() && item->HasMusicInfoTag())
  990. {
  991. CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
  992. dbItem.SetProperty("item_start", item->GetProperty("item_start"));
  993. return IsSamePath(&dbItem);
  994. }
  995. if (item->IsVideoDb() && item->HasVideoInfoTag())
  996. {
  997. CFileItem dbItem(item->m_videoInfoTag->m_strFileNameAndPath, false);
  998. dbItem.SetProperty("item_start", item->GetProperty("item_start"));
  999. return IsSamePath(&dbItem);
  1000. }
  1001. if (HasProperty("original_listitem_url"))
  1002. return (GetProperty("original_listitem_url") == item->GetPath());
  1003. return false;
  1004. }
  1005. bool CFileItem::IsAlbum() const
  1006. {
  1007. return m_bIsAlbum;
  1008. }
  1009. void CFileItem::UpdateInfo(const CFileItem &item, bool replaceLabels /*=true*/)
  1010. {
  1011. if (item.HasVideoInfoTag())
  1012. { // copy info across (TODO: premiered info is normally stored in m_dateTime by the db)
  1013. *GetVideoInfoTag() = *item.GetVideoInfoTag();
  1014. SetOverlayImage(ICON_OVERLAY_UNWATCHED, GetVideoInfoTag()->m_playCount > 0);
  1015. }
  1016. if (item.HasMusicInfoTag())
  1017. *GetMusicInfoTag() = *item.GetMusicInfoTag();
  1018. if (item.HasPictureInfoTag())
  1019. *GetPictureInfoTag() = *item.GetPictureInfoTag();
  1020. if (replaceLabels && !item.GetLabel().IsEmpty())
  1021. SetLabel(item.GetLabel());
  1022. if (replaceLabels && !item.GetLabel2().IsEmpty())
  1023. SetLabel2(item.GetLabel2());
  1024. if (!item.GetThumbnailImage().IsEmpty())
  1025. SetThumbnailImage(item.GetThumbnailImage());
  1026. if (!item.GetIconImage().IsEmpty())
  1027. SetIconImage(item.GetIconImage());
  1028. AppendProperties(item);
  1029. }
  1030. /////////////////////////////////////////////////////////////////////////////////
  1031. /////
  1032. ///// CFileItemList
  1033. /////
  1034. //////////////////////////////////////////////////////////////////////////////////
  1035. CFileItemList::CFileItemList()
  1036. {
  1037. m_fastLookup = false;
  1038. m_bIsFolder = true;
  1039. m_cacheToDisc = CACHE_IF_SLOW;
  1040. m_sortMethod = SORT_METHOD_NONE;
  1041. m_sortOrder = SortOrderNone;
  1042. m_sortIgnoreFolders = false;
  1043. m_replaceListing = false;
  1044. }
  1045. CFileItemList::CFileItemList(const CStdString& strPath) : CFileItem(strPath, true)
  1046. {
  1047. m_fastLookup = false;
  1048. m_cacheToDisc = CACHE_IF_SLOW;
  1049. m_sortMethod = SORT_METHOD_NONE;
  1050. m_sortOrder = SortOrderNone;
  1051. m_sortIgnoreFolders = false;
  1052. m_replaceListing = false;
  1053. }
  1054. CFileItemList::~CFileItemList()
  1055. {
  1056. Clear();
  1057. }
  1058. CFileItemPtr CFileItemList::operator[] (int iItem)
  1059. {
  1060. return Get(iItem);
  1061. }
  1062. const CFileItemPtr CFileItemList::operator[] (int iItem) const
  1063. {
  1064. return Get(iItem);
  1065. }
  1066. CFileItemPtr CFileItemList::operator[] (const CStdString& strPath)
  1067. {
  1068. return Get(strPath);
  1069. }
  1070. const CFileItemPtr CFileItemList::operator[] (const CStdString& strPath) const
  1071. {
  1072. return Get(strPath);
  1073. }
  1074. void CFileItemList::SetFastLookup(bool fastLookup)
  1075. {
  1076. CSingleLock lock(m_lock);
  1077. if (fastLookup && !m_fastLookup)
  1078. { // generate the map
  1079. m_map.clear();
  1080. for (unsigned int i=0; i < m_items.size(); i++)
  1081. {
  1082. CFileItemPtr pItem = m_items[i];
  1083. CStdString path(pItem->GetPath()); path.ToLower();
  1084. m_map.insert(MAPFILEITEMSPAIR(path, pItem));
  1085. }
  1086. }
  1087. if (!fastLookup && m_fastLookup)
  1088. m_map.clear();
  1089. m_fastLookup = fastLookup;
  1090. }
  1091. bool CFileItemList::Contains(const CStdString& fileName) const
  1092. {
  1093. CSingleLock lock(m_lock);
  1094. // checks case insensitive
  1095. CStdString checkPath(fileName); checkPath.ToLower();
  1096. if (m_fastLookup)
  1097. return m_map.find(checkPath) != m_map.end();
  1098. // slow method...
  1099. for (unsigned int i = 0; i < m_items.size(); i++)
  1100. {
  1101. const CFileItemPtr pItem = m_items[i];
  1102. if (pItem->GetPath().Equals(checkPath))
  1103. return true;
  1104. }
  1105. return false;
  1106. }
  1107. void CFileItemList::Clear()
  1108. {
  1109. CSingleLock lock(m_lock);
  1110. ClearItems();
  1111. m_sortMethod = SORT_METHOD_NONE;
  1112. m_sortOrder = SortOrderNone;
  1113. m_sortIgnoreFolders = false;
  1114. m_cacheToDisc = CACHE_IF_SLOW;
  1115. m_sortDetails.clear();
  1116. m_replaceListing = false;
  1117. m_content.Empty();
  1118. }
  1119. void CFileItemList::ClearItems()
  1120. {
  1121. CSingleLock lock(m_lock);
  1122. // make sure we free the memory of the items (these are GUIControls which may have allocated resources)
  1123. FreeMemory();
  1124. for (unsigned int i = 0; i < m_items.size(); i++)
  1125. {
  1126. CFileItemPtr item = m_items[i];
  1127. item->FreeMemory();
  1128. }
  1129. m_items.clear();
  1130. m_map.clear();
  1131. }
  1132. void CFileItemList::Add(const CFileItemPtr &pItem)
  1133. {
  1134. CSingleLock lock(m_lock);
  1135. m_items.push_back(pItem);
  1136. if (m_fastLookup)
  1137. {
  1138. CStdString path(pItem->GetPath());
  1139. path.ToLower();
  1140. m_map.insert(MAPFILEITEMSPAIR(path, pItem));
  1141. }
  1142. }
  1143. void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition)
  1144. {
  1145. CSingleLock lock(m_lock);
  1146. if (itemPosition >= 0)
  1147. {
  1148. m_items.insert(m_items.begin()+itemPosition, pItem);
  1149. }
  1150. else
  1151. {
  1152. m_items.insert(m_items.begin()+(m_items.size()+itemPosition), pItem);
  1153. }
  1154. if (m_fastLookup)
  1155. {
  1156. CStdString path(pItem->GetPath()); path.ToLower();
  1157. m_map.insert(MAPFILEITEMSPAIR(path, pItem));
  1158. }
  1159. }
  1160. void CFileItemList::Remove(CFileItem* pItem)
  1161. {
  1162. CSingleLock lock(m_lock);
  1163. for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it)
  1164. {
  1165. if (pItem == it->get())
  1166. {
  1167. m_items.erase(it);
  1168. if (m_fastLookup)
  1169. {
  1170. CStdString path(pItem->GetPath()); path.ToLower();
  1171. m_map.erase(path);
  1172. }
  1173. break;
  1174. }
  1175. }
  1176. }
  1177. void CFileItemList::Remove(int iItem)
  1178. {
  1179. CSingleLock lock(m_lock);
  1180. if (iItem >= 0 && iItem < (int)Size())
  1181. {
  1182. CFileItemPtr pItem = *(m_items.begin() + iItem);
  1183. if (m_fastLookup)
  1184. {
  1185. CStdString path(pItem->GetPath()); path.ToLower();
  1186. m_map.erase(path);
  1187. }
  1188. m_items.erase(m_items.begin() + iItem);
  1189. }
  1190. }
  1191. void CFileItemList::Append(const CFileItemList& itemlist)
  1192. {
  1193. CSingleLock lock(m_lock);
  1194. for (int i = 0; i < itemlist.Size(); ++i)
  1195. Add(itemlist[i]);
  1196. }
  1197. void CFileItemList::Assign(const CFileItemList& itemlist, bool append)
  1198. {
  1199. CSingleLock lock(m_lock);
  1200. if (!append)
  1201. Clear();
  1202. Append(itemlist);
  1203. SetPath(itemlist.GetPath());
  1204. SetLabel(itemlist.GetLabel());
  1205. m_sortDetails = itemlist.m_sortDetails;
  1206. m_replaceListing = itemlist.m_replaceListing;
  1207. m_content = itemlist.m_content;
  1208. m_mapProperties = itemlist.m_mapProperties;
  1209. m_cacheToDisc = itemlist.m_cacheToDisc;
  1210. }
  1211. bool CFileItemList::Copy(const CFileItemList& items)
  1212. {
  1213. // assign all CFileItem parts
  1214. *(CFileItem*)this = *(CFileItem*)&items;
  1215. // assign the rest of the CFileItemList properties
  1216. m_replaceListing = items.m_replaceListing;
  1217. m_content = items.m_content;
  1218. m_mapProperties = items.m_mapProperties;
  1219. m_cacheToDisc = items.m_cacheToDisc;
  1220. m_sortDetails = items.m_sortDetails;
  1221. m_sortMethod = items.m_sortMethod;
  1222. m_sortOrder = items.m_sortOrder;
  1223. m_sortIgnoreFolders = items.m_sortIgnoreFolders;
  1224. // make a copy of each item
  1225. for (int i = 0; i < items.Size(); i++)
  1226. {
  1227. CFileItemPtr newItem(new CFileItem(*items[i]));
  1228. Add(newItem);
  1229. }
  1230. return true;
  1231. }
  1232. CFileItemPtr CFileItemList::Get(int iItem)
  1233. {
  1234. CSingleLock lock(m_lock);
  1235. if (iItem > -1 && iItem < (int)m_items.size())
  1236. return m_items[iItem];
  1237. return CFileItemPtr();
  1238. }
  1239. const CFileItemPtr CFileItemList::Get(int iItem) const
  1240. {
  1241. CSingleLock lock(m_lock);
  1242. if (iItem > -1 && iItem < (int)m_items.size())
  1243. return m_items[iItem];
  1244. return CFileItemPtr();
  1245. }
  1246. CFileItemPtr CFileItemList::Get(const CStdString& strPath)
  1247. {
  1248. CSingleLock lock(m_lock);
  1249. CStdString pathToCheck(strPath); pathToCheck.ToLower();
  1250. if (m_fastLookup)
  1251. {
  1252. IMAPFILEITEMS it=m_map.find(pathToCheck);
  1253. if (it != m_map.end())
  1254. return it->second;
  1255. return CFileItemPtr();
  1256. }
  1257. // slow method...
  1258. for (unsigned int i = 0; i < m_items.size(); i++)
  1259. {
  1260. CFileItemPtr pItem = m_items[i];
  1261. if (pItem->GetPath().Equals(pathToCheck))
  1262. return pItem;
  1263. }
  1264. return CFileItemPtr();
  1265. }
  1266. const CFileItemPtr CFileItemList::Get(const CStdString& strPath) const
  1267. {
  1268. CSingleLock lock(m_lock);
  1269. CStdString pathToCheck(strPath); pathToCheck.ToLower();
  1270. if (m_fastLookup)
  1271. {
  1272. map<CStdString, CFileItemPtr>::const_iterator it=m_map.find(pathToCheck);
  1273. if (it != m_map.end())
  1274. return it->second;
  1275. return CFileItemPtr();
  1276. }
  1277. // slow method...
  1278. for (unsigned int i = 0; i < m_items.size(); i++)
  1279. {
  1280. CFileItemPtr pItem = m_items[i];
  1281. if (pItem->GetPath().Equals(pathToCheck))
  1282. return pItem;
  1283. }
  1284. return CFileItemPtr();
  1285. }
  1286. int CFileItemList::Size() const
  1287. {
  1288. CSingleLock lock(m_lock);
  1289. return (int)m_items.size();
  1290. }
  1291. bool CFileItemList::IsEmpty() const
  1292. {
  1293. CSingleLock lock(m_lock);
  1294. return (m_items.size() <= 0);
  1295. }
  1296. void CFileItemList::Reserve(int iCount)
  1297. {
  1298. CSingleLock lock(m_lock);
  1299. m_items.reserve(iCount);
  1300. }
  1301. void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func)
  1302. {
  1303. CSingleLock lock(m_lock);
  1304. std::stable_sort(m_items.begin(), m_items.end(), func);
  1305. }
  1306. void CFileItemList::FillSortFields(FILEITEMFILLFUNC func)
  1307. {
  1308. CSingleLock lock(m_lock);
  1309. std::for_each(m_items.begin(), m_items.end(), func);
  1310. }
  1311. void CFileItemList::Sort(SORT_METHOD sortMethod, SortOrder sortOrder)
  1312. {
  1313. // Already sorted?
  1314. if (sortMethod == m_sortMethod && m_sortOrder == sortOrder)
  1315. return;
  1316. SortBy sortBy = SortByNone;
  1317. SortAttribute sortAttributes = SortAttributeNone;
  1318. switch (sortMethod)
  1319. {
  1320. case SORT_METHOD_LABEL:
  1321. case SORT_METHOD_LABEL_IGNORE_FOLDERS:
  1322. case SORT_METHOD_LABEL_IGNORE_THE:
  1323. sortBy = SortByLabel;
  1324. break;
  1325. case SORT_METHOD_DATE:
  1326. sortBy = SortByDate;
  1327. break;
  1328. case SORT_METHOD_SIZE:
  1329. sortBy = SortBySize;
  1330. break;
  1331. case SORT_METHOD_BITRATE:
  1332. sortBy = SortByBitrate;
  1333. break;
  1334. case SORT_METHOD_DRIVE_TYPE:
  1335. sortBy = SortByDriveType;
  1336. break;
  1337. case SORT_METHOD_TRACKNUM:
  1338. sortBy = SortByTrackNumber;
  1339. break;
  1340. case SORT_METHOD_EPISODE:
  1341. sortBy = SortByEpisodeNumber;
  1342. break;
  1343. case SORT_METHOD_DURATION:
  1344. case SORT_METHOD_VIDEO_RUNTIME:
  1345. sortBy = SortByTime;
  1346. break;
  1347. case SORT_METHOD_TITLE:
  1348. case SORT_METHOD_TITLE_IGNORE_THE:
  1349. case SORT_METHOD_VIDEO_TITLE:
  1350. sortBy = SortByTitle;
  1351. break;
  1352. case SORT_METHOD_ARTIST:
  1353. case SORT_METHOD_ARTIST_IGNORE_THE:
  1354. sortBy = SortByArtist;
  1355. break;
  1356. case SORT_METHOD_ALBUM:
  1357. case SORT_METHOD_ALBUM_IGNORE_THE:
  1358. sortBy = SortByAlbum;
  1359. break;
  1360. case SORT_METHOD_GENRE:
  1361. sortBy = SortByGenre;
  1362. break;
  1363. case SORT_METHOD_COUNTRY:
  1364. sortBy = SortByCountry;
  1365. break;
  1366. case SORT_METHOD_DATEADDED:
  1367. sortBy = SortByDateAdded;
  1368. break;
  1369. case SORT_METHOD_FILE:
  1370. sortBy = SortByFile;
  1371. break;
  1372. case SORT_METHOD_SONG_RATING:
  1373. case SORT_METHOD_VIDEO_RATING:
  1374. sortBy = SortByRating;
  1375. break;
  1376. case SORT_METHOD_VIDEO_SORT_TITLE:
  1377. case SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE:
  1378. sortBy = SortBySortTitle;
  1379. break;
  1380. case SORT_METHOD_YEAR:
  1381. sortBy = SortByYear;
  1382. break;
  1383. case SORT_METHOD_PRODUCTIONCODE:
  1384. sortBy = SortByProductionCode;
  1385. break;
  1386. case SORT_METHOD_PROGRAM_COUNT:
  1387. sortBy = SortByProgramCount;
  1388. break;
  1389. case SORT_METHOD_PLAYLIST_ORDER:
  1390. sortBy = SortByPlaylistOrder;
  1391. break;
  1392. case SORT_METHOD_MPAA_RATING:
  1393. sortBy = SortByMPAA;
  1394. break;
  1395. case SORT_METHOD_STUDIO:
  1396. case SORT_METHOD_STUDIO_IGNORE_THE:
  1397. sortBy = SortByStudio;
  1398. break;
  1399. case SORT_METHOD_FULLPATH:
  1400. sortBy = SortByPath;
  1401. break;
  1402. case SORT_METHOD_LASTPLAYED:
  1403. sortBy = SortByLastPlayed;
  1404. break;
  1405. case SORT_METHOD_PLAYCOUNT:
  1406. sortBy = SortByPlaycount;
  1407. break;
  1408. case SORT_METHOD_LISTENERS:
  1409. sortBy = SortByListeners;
  1410. break;
  1411. default:
  1412. CLog::Log(LOGWARNING, "Unknown sort method %d", sortMethod);
  1413. return;
  1414. }
  1415. if (sortMethod == SORT_METHOD_LABEL_IGNORE_THE ||
  1416. sortMethod == SORT_METHOD_TITLE_IGNORE_THE ||
  1417. sortMethod == SORT_METHOD_ARTIST_IGNORE_THE ||
  1418. sortMethod == SORT_METHOD_ALBUM_IGNORE_THE ||
  1419. sortMethod == SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE ||
  1420. sortMethod == SORT_METHOD_STUDIO_IGNORE_THE)
  1421. sortAttributes = (SortAttribute)((int)sortAttributes | SortAttributeIgnoreArticle);
  1422. if (sortMethod == SORT_METHOD_FILE ||
  1423. sortMethod == SORT_METHOD_VIDEO_SORT_TITLE ||
  1424. sortMethod == SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE ||
  1425. sortMethod == SORT_METHOD_LABEL_IGNORE_FOLDERS ||
  1426. sortMethod == SORT_METHOD_DATEADDED ||
  1427. sortMethod == SORT_METHOD_VIDEO_RATING ||
  1428. sortMethod == SORT_METHOD_YEAR ||
  1429. sortMethod == SORT_METHOD_PLAYLIST_ORDER ||
  1430. sortMethod == SORT_METHOD_LASTPLAYED ||
  1431. sortMethod == SORT_METHOD_PLAYCOUNT ||
  1432. m_sortIgnoreFolders)
  1433. sortAttributes = (SortAttribute)((int)sortAttributes | SortAttributeIgnoreFolders);
  1434. if (sortBy == SortByNone)
  1435. return;
  1436. SortItems sortItems((size_t)Size());
  1437. for (int index = 0; index < Size(); index++)
  1438. {
  1439. m_items[index]->ToSortable(sortItems[index]);
  1440. sortItems[index][FieldId] = index;
  1441. }
  1442. // do the sorting
  1443. SortUtils::Sort(sortBy, sortOrder, sortAttributes, sortItems);
  1444. // apply the new order to the existing CFileItems
  1445. VECFILEITEMS sortedFileItems;
  1446. sortedFileItems.reserve(Size());
  1447. for (SortItems::const_iterator it = sortItems.begin(); it != sortItems.end(); it++)
  1448. {
  1449. CFileItemPtr item = m_items[(int)it->at(FieldId).asInteger()];
  1450. // Set the sort label in the CFileItem
  1451. item->SetSortLabel(CStdStringW(it->at(FieldSort).asWideString()));
  1452. sortedFileItems.push_back(item);
  1453. }
  1454. // replace the current list with the re-ordered one
  1455. m_items.assign(sortedFileItems.begin(), sortedFileItems.end());
  1456. m_sortMethod = sortMethod;
  1457. m_sortOrder = sortOrder;
  1458. }
  1459. void CFileItemList::Randomize()
  1460. {
  1461. CSingleLock lock(m_lock);
  1462. random_shuffle(m_items.begin(), m_items.end());
  1463. }
  1464. void CFileItemList::Archive(CArchive& ar)
  1465. {
  1466. CSingleLock lock(m_lock);
  1467. if (ar.IsStoring())
  1468. {
  1469. CFileItem::Archive(ar);
  1470. int i = 0;
  1471. if (m_items.size() > 0 && m_items[0]->IsParentFolder())
  1472. i = 1;
  1473. ar << (int)(m_items.size() - i);
  1474. ar << m_fastLookup;
  1475. ar << (int)m_sortMethod;
  1476. ar << (int)m_sortOrder;
  1477. ar << m_sortIgnoreFolders;
  1478. ar << (int)m_cacheToDisc;
  1479. ar << (int)m_sortDetails.size();
  1480. for (unsigned int j = 0; j < m_sortDetails.size(); ++j)
  1481. {
  1482. const SORT_METHOD_DETAILS &details = m_sortDetails[j];
  1483. ar << (int)details.m_sortMethod;
  1484. ar << details.m_buttonLabel;
  1485. ar << details.m_labelMasks.m_strLabelFile;
  1486. ar << details.m_labelMasks.m_strLabelFolder;
  1487. ar << details.m_labelMasks.m_strLabel2File;
  1488. ar << details.m_labelMasks.m_strLabel2Folder;
  1489. }
  1490. ar << m_content;
  1491. for (; i < (int)m_items.size(); ++i)
  1492. {
  1493. CFileItemPtr pItem = m_items[i];
  1494. ar << *pItem;
  1495. }
  1496. }
  1497. else
  1498. {
  1499. CFileItemPtr pParent;
  1500. if (!IsEmpty())
  1501. {
  1502. CFileItemPtr pItem=m_items[0];
  1503. if (pItem->IsParentFolder())
  1504. pParent.reset(new CFileItem(*pItem));
  1505. }
  1506. SetFastLookup(false);
  1507. Clear();
  1508. CFileItem::Archive(ar);
  1509. int iSize = 0;
  1510. ar >> iSize;
  1511. if (iSize <= 0)
  1512. return ;
  1513. if (pParent)
  1514. {
  1515. m_items.reserve(iSize + 1);
  1516. m_items.push_back(pParent);
  1517. }
  1518. else
  1519. m_items.reserve(iSize);
  1520. bool fastLookup=false;
  1521. ar >> fastLookup;
  1522. int tempint;
  1523. ar >> (int&)tempint;
  1524. m_sortMethod = SORT_METHOD(tempint);
  1525. ar >> (int&)tempint;
  1526. m_sortOrder = SortOrder(tempint);
  1527. ar >> m_sortIgnoreFolders;
  1528. ar >> (int&)tempint;
  1529. m_cacheToDisc = CACHE_TYPE(tempint);
  1530. unsigned int detailSize = 0;
  1531. ar >> detailSize;
  1532. for (unsigned int j = 0; j < detailSize; ++j)
  1533. {
  1534. SORT_METHOD_DETAILS details;
  1535. ar >> (int&)tempint;
  1536. details.m_sortMethod = SORT_METHOD(tempint);
  1537. ar >> details.m_buttonLabel;
  1538. ar >> details.m_labelMasks.m_strLabelFile;
  1539. ar >> details.m_labelMasks.m_strLabelFolder;
  1540. ar >> details.m_labelMasks.m_strLabel2File;
  1541. ar >> details.m_labelMasks.m_strLabel2Folder;
  1542. m_sortDetails.push_back(details);
  1543. }
  1544. ar >> m_content;
  1545. for (int i = 0; i < iSize; ++i)
  1546. {
  1547. CFileItemPtr pItem(new CFileItem);
  1548. ar >> *pItem;
  1549. Add(pItem);
  1550. }
  1551. SetFastLookup(fastLookup);
  1552. }
  1553. }
  1554. void CFileItemList::FillInDefaultIcons()
  1555. {
  1556. CSingleLock lock(m_lock);
  1557. for (int i = 0; i < (int)m_items.size(); ++i)
  1558. {
  1559. CFileItemPtr pItem = m_items[i];
  1560. pItem->FillInDefaultIcon();
  1561. }
  1562. }
  1563. int CFileItemList::GetFolderCount() const
  1564. {
  1565. CSingleLock lock(m_lock);
  1566. int nFolderCount = 0;
  1567. for (int i = 0; i < (int)m_items.size(); i++)
  1568. {
  1569. CFileItemPtr pItem = m_items[i];
  1570. if (pItem->m_bIsFolder)
  1571. nFolderCount++;
  1572. }
  1573. return nFolderCount;
  1574. }
  1575. int CFileItemList::GetObjectCount() const
  1576. {
  1577. CSingleLock lock(m_lock);
  1578. int numObjects = (int)m_items.size();
  1579. if (numObjects && m_items[0]->IsParentFolder())
  1580. numObjects--;
  1581. return numObjects;
  1582. }
  1583. int CFileItemList::GetFileCount() const
  1584. {
  1585. CSingleLock lock(m_lock);
  1586. int nFileCount = 0;
  1587. for (int i = 0; i < (int)m_items.size(); i++)
  1588. {
  1589. CFileItemPtr pItem = m_items[i];
  1590. if (!pItem->m_bIsFolder)
  1591. nFileCount++;
  1592. }
  1593. return nFileCount;
  1594. }
  1595. int CFileItemList::GetSelectedCount() const
  1596. {
  1597. CSingleLock lock(m_lock);
  1598. int count = 0;
  1599. for (int i = 0; i < (int)m_items.size(); i++)
  1600. {
  1601. CFileItemPtr pItem = m_items[i];
  1602. if (pItem->IsSelected())
  1603. count++;
  1604. }
  1605. return count;
  1606. }
  1607. void CFileItemList::FilterCueItems()
  1608. {
  1609. CSingleLock lock(m_lock);
  1610. // Handle .CUE sheet files...
  1611. VECSONGS itemstoadd;
  1612. CStdStringArray itemstodelete;
  1613. for (int i = 0; i < (int)m_items.size(); i++)
  1614. {
  1615. CFileItemPtr pItem = m_items[i];
  1616. if (!pItem->m_bIsFolder)
  1617. { // see if it's a .CUE sheet
  1618. if (pItem->IsCUESheet())
  1619. {
  1620. CCueDocument cuesheet;
  1621. if (cuesheet.Parse(pItem->GetPath()))
  1622. {
  1623. VECSONGS newitems;
  1624. cuesheet.GetSongs(newitems);
  1625. std::vector<CStdString> MediaFileVec;
  1626. cuesheet.GetMediaFiles(MediaFileVec);
  1627. // queue the cue sheet and the underlying media file for deletion
  1628. for(std::vector<CStdString>::iterator itMedia = MediaFileVec.begin(); itMedia != MediaFileVec.end(); itMedia++)
  1629. {
  1630. CStdString strMediaFile = *itMedia;
  1631. CStdString fileFromCue = strMediaFile; // save the file from the cue we're matching against,
  1632. // as we're going to search for others here...
  1633. bool bFoundMediaFile = CFile::Exists(strMediaFile);
  1634. // queue the cue sheet and the underlying media file for deletion
  1635. if (!bFoundMediaFile)
  1636. {
  1637. // try file in same dir, not matching case...
  1638. if (Contains(strMediaFile))
  1639. {
  1640. bFoundMediaFile = true;
  1641. }
  1642. else
  1643. {
  1644. // try removing the .cue extension...
  1645. strMediaFile = pItem->GetPath();
  1646. URIUtils::RemoveExtension(strMediaFile);
  1647. CFileItem item(strMediaFile, false);
  1648. if (item.IsAudio() && Contains(strMediaFile))
  1649. {
  1650. bFoundMediaFile = true;
  1651. }
  1652. else
  1653. { // try replacing the extension with one of our allowed ones.
  1654. CStdStringArray extensions;
  1655. StringUtils::SplitString(g_settings.m_musicExtensions, "|", extensions);
  1656. for (unsigned int i = 0; i < extensions.size(); i++)
  1657. {
  1658. strMediaFile = URIUtils::ReplaceExtension(pItem->GetPath(), extensions[i]);
  1659. CFileItem item(strMediaFile, false);
  1660. if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile))
  1661. {
  1662. bFoundMediaFile = true;
  1663. break;
  1664. }
  1665. }
  1666. }
  1667. }
  1668. }
  1669. if (bFoundMediaFile)
  1670. {
  1671. itemstodelete.push_back(pItem->GetPath());
  1672. itemstodelete.push_back(strMediaFile);
  1673. // get the additional stuff (year, genre etc.) from the underlying media files tag.
  1674. CMusicInfoTag tag;
  1675. auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(strMediaFile));
  1676. if (NULL != pLoader.get())
  1677. {
  1678. // get id3tag
  1679. pLoader->Load(strMediaFile, tag);
  1680. }
  1681. // fill in any missing entries from underlying media file
  1682. for (int j = 0; j < (int)newitems.size(); j++)
  1683. {
  1684. CSong song = newitems[j];
  1685. // only for songs that actually match the current media file
  1686. if (song.strFileName == fileFromCue)
  1687. {
  1688. // we might have a new media file from the above matching code
  1689. song.strFileName = strMediaFile;
  1690. if (tag.Loaded())
  1691. {
  1692. if (song.strAlbum.empty() && !tag.GetAlbum().empty()) song.strAlbum = tag.GetAlbum();
  1693. if (song.albumArtist.empty() && !tag.GetAlbumArtist().empty()) song.albumArtist = tag.GetAlbumArtist();
  1694. if (song.genre.empty() && !tag.GetGenre().empty()) song.genre = tag.GetGenre();
  1695. if (song.artist.empty() && !tag.GetArtist().empty()) song.artist = tag.GetArtist();
  1696. if (tag.GetDiscNumber()) song.iTrack |= (tag.GetDiscNumber() << 16); // see CMusicInfoTag::GetDiscNumber()
  1697. SYSTEMTIME dateTime;
  1698. tag.GetReleaseDate(dateTime);
  1699. if (dateTime.wYear) song.iYear = dateTime.wYear;
  1700. if (song.embeddedArt.empty() && !tag.GetCoverArtInfo().empty())
  1701. song.embeddedArt = tag.GetCoverArtInfo();
  1702. }
  1703. if (!song.iDuration && tag.GetDuration() > 0)
  1704. { // must be the last song
  1705. song.iDuration = (tag.GetDuration() * 75 - song.iStartOffset + 37) / 75;
  1706. }
  1707. // add this item to the list
  1708. itemstoadd.push_back(song);
  1709. }
  1710. }
  1711. }
  1712. else
  1713. { // remove the .cue sheet from the directory
  1714. itemstodelete.push_back(pItem->GetPath());
  1715. }
  1716. }
  1717. }
  1718. else
  1719. { // remove the .cue sheet from the directory (can't parse it - no point listing it)
  1720. itemstodelete.push_back(pItem->GetPath());
  1721. }
  1722. }
  1723. }
  1724. }
  1725. // now delete the .CUE files and underlying media files.
  1726. for (int i = 0; i < (int)itemstodelete.size(); i++)
  1727. {
  1728. for (int j = 0; j < (int)m_items.size(); j++)
  1729. {
  1730. CFileItemPtr pItem = m_items[j];
  1731. if (stricmp(pItem->GetPath().c_str(), itemstodelete[i].c_str()) == 0)
  1732. { // delete this item
  1733. m_items.erase(m_items.begin() + j);
  1734. break;
  1735. }
  1736. }
  1737. }
  1738. // and add the files from the .CUE sheet
  1739. for (int i = 0; i < (int)itemstoadd.size(); i++)
  1740. {
  1741. // now create the file item, and add to the item list.
  1742. CFileItemPtr pItem(new CFileItem(itemstoadd[i]));
  1743. m_items.push_back(pItem);
  1744. }
  1745. }
  1746. // Remove the extensions from the filenames
  1747. void CFileItemList::RemoveExtensions()
  1748. {
  1749. CSingleLock lock(m_lock);
  1750. for (int i = 0; i < Size(); ++i)
  1751. m_items[i]->RemoveExtension();
  1752. }
  1753. void CFileItemList::Stack(bool stackFiles /* = true */)
  1754. {
  1755. CSingleLock lock(m_lock);
  1756. // not allowed here
  1757. if (IsVirtualDirectoryRoot() || IsLiveTV() || IsSourcesPath())
  1758. return;
  1759. SetProperty("isstacked", true);
  1760. // items needs to be sorted for stuff below to work properly
  1761. Sort(SORT_METHOD_LABEL, SortOrderAscending);
  1762. StackFolders();
  1763. if (stackFiles)
  1764. StackFiles();
  1765. }
  1766. void CFileItemList::StackFolders()
  1767. {
  1768. // Precompile our REs
  1769. VECCREGEXP folderRegExps;
  1770. CRegExp folderRegExp(true);
  1771. const CStdStringArray& strFolderRegExps = g_advancedSettings.m_folderStackRegExps;
  1772. CStdStringArray::const_iterator strExpression = strFolderRegExps.begin();
  1773. while (strExpression != strFolderRegExps.end())
  1774. {
  1775. if (!folderRegExp.RegComp(*strExpression))
  1776. CLog::Log(LOGERROR, "%s: Invalid folder stack RegExp:'%s'", __FUNCTION__, strExpression->c_str());
  1777. else
  1778. folderRegExps.push_back(folderRegExp);
  1779. strExpression++;
  1780. }
  1781. // stack folders
  1782. for (int i = 0; i < Size(); i++)
  1783. {
  1784. CFileItemPtr item = Get(i);
  1785. // combined the folder checks
  1786. if (item->m_bIsFolder)
  1787. {
  1788. // only check known fast sources?
  1789. // NOTES:
  1790. // 1. rars and zips may be on slow sources? is this supposed to be allowed?
  1791. if( !item->IsRemote()
  1792. || item->IsSmb()
  1793. || item->IsNfs()
  1794. || item->IsAfp()
  1795. || URIUtils::IsInRAR(item->GetPath())
  1796. || URIUtils::IsInZIP(item->GetPath())
  1797. || URIUtils::IsOnLAN(item->GetPath())
  1798. )
  1799. {
  1800. // stack cd# folders if contains only a single video file
  1801. bool bMatch(false);
  1802. VECCREGEXP::iterator expr = folderRegExps.begin();
  1803. while (!bMatch && expr != folderRegExps.end())
  1804. {
  1805. //CLog::Log(LOGDEBUG,"%s: Running expression %s on %s", __FUNCTION__, expr->GetPattern().c_str(), item->GetLabel().c_str());
  1806. bMatch = (expr->RegFind(item->GetLabel().c_str()) != -1);
  1807. if (bMatch)
  1808. {
  1809. CFileItemList items;
  1810. CDirectory::GetDirectory(item->GetPath(),items,g_settings.m_videoExtensions);
  1811. // optimized to only traverse listing once by checking for filecount
  1812. // and recording last file item for later use
  1813. int nFiles = 0;
  1814. int index = -1;
  1815. for (int j = 0; j < items.Size(); j++)
  1816. {
  1817. if (!items[j]->m_bIsFolder)
  1818. {
  1819. nFiles++;
  1820. index = j;
  1821. }
  1822. if (nFiles > 1)
  1823. break;
  1824. }
  1825. if (nFiles == 1)
  1826. *item = *items[index];
  1827. }
  1828. expr++;
  1829. }
  1830. // check for dvd folders
  1831. if (!bMatch)
  1832. {
  1833. CStdString path;
  1834. CStdString dvdPath;
  1835. URIUtils::AddFileToFolder(item->GetPath(), "VIDEO_TS.IFO", path);
  1836. if (CFile::Exists(path))
  1837. dvdPath = path;
  1838. else
  1839. {
  1840. URIUtils::AddFileToFolder(item->GetPath(), "VIDEO_TS", dvdPath);
  1841. URIUtils::AddFileToFolder(dvdPath, "VIDEO_TS.IFO", path);
  1842. dvdPath.Empty();
  1843. if (CFile::Exists(path))
  1844. dvdPath = path;
  1845. }
  1846. #ifdef HAVE_LIBBLURAY
  1847. if (dvdPath.IsEmpty())
  1848. {
  1849. URIUtils::AddFileToFolder(item->GetPath(), "index.bdmv", path);
  1850. if (CFile::Exists(path))
  1851. dvdPath = path;
  1852. else
  1853. {
  1854. URIUtils::AddFileToFolder(item->GetPath(), "BDMV", dvdPath);
  1855. URIUtils::AddFileToFolder(dvdPath, "index.bdmv", path);
  1856. dvdPath.Empty();
  1857. if (CFile::Exists(path))
  1858. dvdPath = path;
  1859. }
  1860. }
  1861. #endif
  1862. if (!dvdPath.IsEmpty())
  1863. {
  1864. // NOTE: should this be done for the CD# folders too?
  1865. item->m_bIsFolder = false;
  1866. item->SetPath(dvdPath);
  1867. item->SetLabel2("");
  1868. item->SetLabelPreformated(true);
  1869. m_sortMethod = SORT_METHOD_NONE; /* sorting is now broken */
  1870. }
  1871. }
  1872. }
  1873. }
  1874. }
  1875. }
  1876. void CFileItemList::StackFiles()
  1877. {
  1878. // Precompile our REs
  1879. VECCREGEXP stackRegExps;
  1880. CRegExp tmpRegExp(true);
  1881. const CStdStringArray& strStackRegExps = g_advancedSettings.m_videoStackRegExps;
  1882. CStdStringArray::const_iterator strRegExp = strStackRegExps.begin();
  1883. while (strRegExp != strStackRegExps.end())
  1884. {
  1885. if (tmpRegExp.RegComp(*strRegExp))
  1886. {
  1887. if (tmpRegExp.GetCaptureTotal() == 4)
  1888. stackRegExps.push_back(tmpRegExp);
  1889. else
  1890. CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have 4 captures.", strRegExp->c_str());
  1891. }
  1892. strRegExp++;
  1893. }
  1894. // now stack the files, some of which may be from the previous stack iteration
  1895. int i = 0;
  1896. while (i < Size())
  1897. {
  1898. CFileItemPtr item1 = Get(i);
  1899. // skip folders, nfo files, playlists
  1900. if (item1->m_bIsFolder
  1901. || item1->IsParentFolder()
  1902. || item1->IsNFO()
  1903. || item1->IsPlayList()
  1904. )
  1905. {
  1906. // increment index
  1907. i++;
  1908. continue;
  1909. }
  1910. int64_t size = 0;
  1911. size_t offset = 0;
  1912. CStdString stackName;
  1913. CStdString file1;
  1914. CStdString filePath;
  1915. vector<int> stack;
  1916. VECCREGEXP::iterator expr = stackRegExps.begin();
  1917. URIUtils::Split(item1->GetPath(), filePath, file1);
  1918. if (URIUtils::ProtocolHasEncodedFilename(CURL(filePath).GetProtocol() ) )
  1919. CURL::Decode(file1);
  1920. int j;
  1921. while (expr != stackRegExps.end())
  1922. {
  1923. if (expr->RegFind(file1, offset) != -1)
  1924. {
  1925. CStdString Title1 = expr->GetMatch(1),
  1926. Volume1 = expr->GetMatch(2),
  1927. Ignore1 = expr->GetMatch(3),
  1928. Extension1 = expr->GetMatch(4);
  1929. if (offset)
  1930. Title1 = file1.substr(0, expr->GetSubStart(2));
  1931. j = i + 1;
  1932. while (j < Size())
  1933. {
  1934. CFileItemPtr item2 = Get(j);
  1935. // skip folders, nfo files, playlists
  1936. if (item2->m_bIsFolder
  1937. || item2->IsParentFolder()
  1938. || item2->IsNFO()
  1939. || item2->IsPlayList()
  1940. )
  1941. {
  1942. // increment index
  1943. j++;
  1944. continue;
  1945. }
  1946. CStdString file2, filePath2;
  1947. URIUtils::Split(item2->GetPath(), filePath2, file2);
  1948. if (URIUtils::ProtocolHasEncodedFilename(CURL(filePath2).GetProtocol() ) )
  1949. CURL::Decode(file2);
  1950. if (expr->RegFind(file2, offset) != -1)
  1951. {
  1952. CStdString Title2 = expr->GetMatch(1),
  1953. Volume2 = expr->GetMatch(2),
  1954. Ignore2 = expr->GetMatch(3),
  1955. Extension2 = expr->GetMatch(4);
  1956. if (offset)
  1957. Title2 = file2.substr(0, expr->GetSubStart(2));
  1958. if (Title1.Equals(Title2))
  1959. {
  1960. if (!Volume1.Equals(Volume2))
  1961. {
  1962. if (Ignore1.Equals(Ignore2) && Extension1.Equals(Extension2))
  1963. {
  1964. if (stack.size() == 0)
  1965. {
  1966. stackName = Title1 + Ignore1 + Extension1;
  1967. stack.push_back(i);
  1968. size += item1->m_dwSize;
  1969. }
  1970. stack.push_back(j);
  1971. size += item2->m_dwSize;
  1972. }
  1973. else // Sequel
  1974. {
  1975. offset = 0;
  1976. expr++;
  1977. break;
  1978. }
  1979. }
  1980. else if (!Ignore1.Equals(Ignore2)) // False positive, try again with offset
  1981. {
  1982. offset = expr->GetSubStart(3);
  1983. break;
  1984. }
  1985. else // Extension mismatch
  1986. {
  1987. offset = 0;
  1988. expr++;
  1989. break;
  1990. }
  1991. }
  1992. else // Title mismatch
  1993. {
  1994. offset = 0;
  1995. expr++;
  1996. break;
  1997. }
  1998. }
  1999. else // No match 2, next expression
  2000. {
  2001. offset = 0;
  2002. expr++;
  2003. break;
  2004. }
  2005. j++;
  2006. }
  2007. if (j == Size())
  2008. expr = stackRegExps.end();
  2009. }
  2010. else // No match 1
  2011. {
  2012. offset = 0;
  2013. expr++;
  2014. }
  2015. if (stack.size() > 1)
  2016. {
  2017. // have a stack, remove the items and add the stacked item
  2018. // dont actually stack a multipart rar set, just remove all items but the first
  2019. CStdString stackPath;
  2020. if (Get(stack[0])->IsRAR())
  2021. stackPath = Get(stack[0])->GetPath();
  2022. else
  2023. {
  2024. CStackDirectory dir;
  2025. stackPath = dir.ConstructStackPath(*this, stack);
  2026. }
  2027. item1->SetPath(stackPath);
  2028. // clean up list
  2029. for (unsigned k = 1; k < stack.size(); k++)
  2030. Remove(i+1);
  2031. // item->m_bIsFolder = true; // don't treat stacked files as folders
  2032. // the label may be in a different char set from the filename (eg over smb
  2033. // the label is converted from utf8, but the filename is not)
  2034. if (!g_guiSettings.GetBool("filelists.showextensions"))
  2035. URIUtils::RemoveExtension(stackName);
  2036. item1->SetLabel(stackName);
  2037. item1->m_dwSize = size;
  2038. break;
  2039. }
  2040. }
  2041. i++;
  2042. }
  2043. }
  2044. bool CFileItemList::Load(int windowID)
  2045. {
  2046. CFile file;
  2047. if (file.Open(GetDiscFileCache(windowID)))
  2048. {
  2049. CLog::Log(LOGDEBUG,"Loading fileitems [%s]",GetPath().c_str());
  2050. CArchive ar(&file, CArchive::load);
  2051. ar >> *this;
  2052. CLog::Log(LOGDEBUG," -- items: %i, directory: %s sort method: %i, ascending: %s",Size(),GetPath().c_str(), m_sortMethod, m_sortOrder ? "true" : "false");
  2053. ar.Close();
  2054. file.Close();
  2055. return true;
  2056. }
  2057. return false;
  2058. }
  2059. bool CFileItemList::Save(int windowID)
  2060. {
  2061. int iSize = Size();
  2062. if (iSize <= 0)
  2063. return false;
  2064. CLog::Log(LOGDEBUG,"Saving fileitems [%s]",GetPath().c_str());
  2065. CFile file;
  2066. if (file.OpenForWrite(GetDiscFileCache(windowID), true)) // overwrite always
  2067. {
  2068. CArchive ar(&file, CArchive::store);
  2069. ar << *this;
  2070. CLog::Log(LOGDEBUG," -- items: %i, sort method: %i, ascending: %s",iSize,m_sortMethod, m_sortOrder ? "true" : "false");
  2071. ar.Close();
  2072. file.Close();
  2073. return true;
  2074. }
  2075. return false;
  2076. }
  2077. void CFileItemList::RemoveDiscCache(int windowID) const
  2078. {
  2079. CStdString cacheFile(GetDiscFileCache(windowID));
  2080. if (CFile::Exists(cacheFile))
  2081. {
  2082. CLog::Log(LOGDEBUG,"Clearing cached fileitems [%s]",GetPath().c_str());
  2083. CFile::Delete(cacheFile);
  2084. }
  2085. }
  2086. CStdString CFileItemList::GetDiscFileCache(int windowID) const
  2087. {
  2088. CStdString strPath(GetPath());
  2089. URIUtils::RemoveSlashAtEnd(strPath);
  2090. Crc32 crc;
  2091. crc.ComputeFromLowerCase(strPath);
  2092. CStdString cacheFile;
  2093. if (IsCDDA() || IsOnDVD())
  2094. cacheFile.Format("special://temp/r-%08x.fi", (unsigned __int32)crc);
  2095. else if (IsMusicDb())
  2096. cacheFile.Format("special://temp/mdb-%08x.fi", (unsigned __int32)crc);
  2097. else if (IsVideoDb())
  2098. cacheFile.Format("special://temp/vdb-%08x.fi", (unsigned __int32)crc);
  2099. else if (IsSmartPlayList())
  2100. cacheFile.Format("special://temp/sp-%08x.fi", (unsigned __int32)crc);
  2101. else if (windowID)
  2102. cacheFile.Format("special://temp/%i-%08x.fi", windowID, (unsigned __int32)crc);
  2103. else
  2104. cacheFile.Format("special://temp/%08x.fi", (unsigned __int32)crc);
  2105. return cacheFile;
  2106. }
  2107. bool CFileItemList::AlwaysCache() const
  2108. {
  2109. // some database folders are always cached
  2110. if (IsMusicDb())
  2111. return CMusicDatabaseDirectory::CanCache(GetPath());
  2112. if (IsVideoDb())
  2113. return CVideoDatabaseDirectory::CanCache(GetPath());
  2114. return false;
  2115. }
  2116. CStdString CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */) const
  2117. {
  2118. if (m_strPath.IsEmpty()
  2119. || m_bIsShareOrDrive
  2120. || IsInternetStream()
  2121. || URIUtils::IsUPnP(m_strPath)
  2122. || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
  2123. || IsPlugin()
  2124. || IsAddonsPath()
  2125. || IsParentFolder()
  2126. || IsMusicDb())
  2127. return "";
  2128. // we first check for <filename>.tbn or <foldername>.tbn
  2129. CStdString fileThumb(GetTBNFile());
  2130. if (CFile::Exists(fileThumb))
  2131. return fileThumb;
  2132. // if a folder, check for folder.jpg
  2133. if (m_bIsFolder && !IsFileFolder() && (!IsRemote() || alwaysCheckRemote || g_guiSettings.GetBool("musicfiles.findremotethumbs")))
  2134. {
  2135. CStdStringArray thumbs;
  2136. StringUtils::SplitString(g_advancedSettings.m_musicThumbs, "|", thumbs);
  2137. for (unsigned int i = 0; i < thumbs.size(); ++i)
  2138. {
  2139. CStdString folderThumb(GetFolderThumb(thumbs[i]));
  2140. if (CFile::Exists(folderThumb))
  2141. {
  2142. return folderThumb;
  2143. }
  2144. }
  2145. }
  2146. // No thumb found
  2147. return "";
  2148. }
  2149. // Gets the .tbn filename from a file or folder name.
  2150. // <filename>.ext -> <filename>.tbn
  2151. // <foldername>/ -> <foldername>.tbn
  2152. CStdString CFileItem::GetTBNFile() const
  2153. {
  2154. CStdString thumbFile;
  2155. CStdString strFile = m_strPath;
  2156. if (IsStack())
  2157. {
  2158. CStdString strPath, strReturn;
  2159. URIUtils::GetParentPath(m_strPath,strPath);
  2160. CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
  2161. CStdString strTBNFile = item.GetTBNFile();
  2162. URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strReturn);
  2163. if (CFile::Exists(strReturn))
  2164. return strReturn;
  2165. URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)),strFile);
  2166. }
  2167. if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
  2168. {
  2169. CStdString strPath, strParent;
  2170. URIUtils::GetDirectory(strFile,strPath);
  2171. URIUtils::GetParentPath(strPath,strParent);
  2172. URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
  2173. }
  2174. CURL url(strFile);
  2175. strFile = url.GetFileName();
  2176. if (m_bIsFolder && !IsFileFolder())
  2177. URIUtils::RemoveSlashAtEnd(strFile);
  2178. if (!strFile.IsEmpty())
  2179. {
  2180. if (m_bIsFolder && !IsFileFolder())
  2181. thumbFile = strFile + ".tbn"; // folder, so just add ".tbn"
  2182. else
  2183. thumbFile = URIUtils::ReplaceExtension(strFile, ".tbn");
  2184. url.SetFileName(thumbFile);
  2185. thumbFile = url.Get();
  2186. }
  2187. return thumbFile;
  2188. }
  2189. CStdString CFileItem::GetUserVideoThumb() const
  2190. {
  2191. if (IsTuxBox())
  2192. {
  2193. if (!m_bIsFolder)
  2194. return g_tuxbox.GetPicon(GetLabel());
  2195. else return "";
  2196. }
  2197. if (m_strPath.IsEmpty()
  2198. || m_bIsShareOrDrive
  2199. || IsInternetStream()
  2200. || URIUtils::IsUPnP(m_strPath)
  2201. || (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
  2202. || IsPlugin()
  2203. || IsAddonsPath()
  2204. || IsParentFolder()
  2205. || IsLiveTV()
  2206. || IsDVD())
  2207. return "";
  2208. // 1. check <filename>.tbn or <foldername>.tbn
  2209. CStdString fileThumb(GetTBNFile());
  2210. if (CFile::Exists(fileThumb))
  2211. return fileThumb;
  2212. if (IsOpticalMediaFile())
  2213. { // special case for optical media "folders" - check the parent folder (or parent of parent)
  2214. // TODO: A better way to handle this would be to treat stacked folders as folders rather than files.
  2215. CFileItem item(GetLocalMetadataPath(), true);
  2216. CStdString thumb(item.GetUserVideoThumb());
  2217. if (!thumb.IsEmpty())
  2218. return thumb;
  2219. }
  2220. // 2. - check movie.tbn, as long as it's not a folder
  2221. if (!m_bIsFolder)
  2222. {
  2223. CStdString strPath, movietbnFile;
  2224. URIUtils::GetParentPath(m_strPath, strPath);
  2225. URIUtils::AddFileToFolder(strPath, "movie.tbn", movietbnFile);
  2226. if (CFile::Exists(movietbnFile))
  2227. return movietbnFile;
  2228. }
  2229. // 3. check folder image in_m_dvdThumbs (folder.jpg)
  2230. if (m_bIsFolder && !IsFileFolder())
  2231. {
  2232. CStdStringArray thumbs;
  2233. StringUtils::SplitString(g_advancedSettings.m_dvdThumbs, "|", thumbs);
  2234. for (unsigned int i = 0; i < thumbs.size(); ++i)
  2235. {
  2236. CStdString folderThumb(GetFolderThumb(thumbs[i]));
  2237. if (CFile::Exists(folderThumb))
  2238. {
  2239. return folderThumb;
  2240. }
  2241. }
  2242. }
  2243. // No thumb found
  2244. return "";
  2245. }
  2246. CStdString CFileItem::GetFolderThumb(const CStdString &folderJPG /* = "folder.jpg" */) const
  2247. {
  2248. CStdString folderThumb;
  2249. CStdString strFolder = m_strPath;
  2250. if (IsStack() ||
  2251. URIUtils::IsInRAR(strFolder) ||
  2252. URIUtils::IsInZIP(strFolder))
  2253. {
  2254. URIUtils::GetParentPath(m_strPath,strFolder);
  2255. }
  2256. if (IsMultiPath())
  2257. strFolder = CMultiPathDirectory::GetFirstPath(m_strPath);
  2258. URIUtils::AddFileToFolder(strFolder, folderJPG, folderThumb);
  2259. return folderThumb;
  2260. }
  2261. CStdString CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const
  2262. {
  2263. if (IsLabelPreformated())
  2264. return GetLabel();
  2265. CStdString strMovieName = GetBaseMoviePath(bUseFolderNames);
  2266. if (URIUtils::IsStack(strMovieName))
  2267. strMovieName = CStackDirectory::GetStackedTitlePath(strMovieName);
  2268. URIUtils::RemoveSlashAtEnd(strMovieName);
  2269. strMovieName = URIUtils::GetFileName(strMovieName);
  2270. CURL::Decode(strMovieName);
  2271. return strMovieName;
  2272. }
  2273. CStdString CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
  2274. {
  2275. CStdString strMovieName = m_strPath;
  2276. if (IsMultiPath())
  2277. strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
  2278. if (IsOpticalMediaFile())
  2279. return GetLocalMetadataPath();
  2280. if ((!m_bIsFolder || URIUtils::IsInArchive(m_strPath)) && bUseFolderNames)
  2281. {
  2282. CStdString name2(strMovieName);
  2283. URIUtils::GetParentPath(name2,strMovieName);
  2284. if (URIUtils::IsInArchive(m_strPath))
  2285. {
  2286. CStdString strArchivePath;
  2287. URIUtils::GetParentPath(strMovieName, strArchivePath);
  2288. strMovieName = strArchivePath;
  2289. }
  2290. }
  2291. return strMovieName;
  2292. }
  2293. #ifdef UNIT_TESTING
  2294. bool CFileItem::testGetBaseMoviePath()
  2295. {
  2296. typedef struct
  2297. {
  2298. const char *file;
  2299. bool use_folder;
  2300. const char *base;
  2301. } testfiles;
  2302. const testfiles test_files[] = {{ "c:\\dir\\filename.avi", false, "c:\\dir\\filename.avi" },
  2303. { "c:\\dir\\filename.avi", true, "c:\\dir\\" },
  2304. { "/dir/filename.avi", false, "/dir/filename.avi" },
  2305. { "/dir/filename.avi", true, "/dir/" },
  2306. { "smb://somepath/file.avi", false, "smb://somepath/file.avi" },
  2307. { "smb://somepath/file.avi", true, "smb://somepath/" },
  2308. { "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi", false, "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi" },
  2309. { "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi", true, "/path/to/movie_name/" },
  2310. { "/home/user/TV Shows/Dexter/S1/1x01.avi", false, "/home/user/TV Shows/Dexter/S1/1x01.avi" },
  2311. { "/home/user/TV Shows/Dexter/S1/1x01.avi", true, "/home/user/TV Shows/Dexter/S1/" },
  2312. { "rar://g%3a%5cmultimedia%5cmovies%5cSphere%2erar/Sphere.avi", true, "g:\\multimedia\\movies\\" },
  2313. { "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", false, "/home/user/movies/movie_name/" },
  2314. { "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", true, "/home/user/movies/movie_name/" },
  2315. { "/home/user/movies/movie_name/BDMV/index.bdmv", false, "/home/user/movies/movie_name/" },
  2316. { "/home/user/movies/movie_name/BDMV/index.bdmv", true, "/home/user/movies/movie_name/" }};
  2317. for (unsigned int i = 0; i < sizeof(test_files) / sizeof(testfiles); i++)
  2318. {
  2319. CFileItem item;
  2320. item.SetPath(test_files[i].file);
  2321. CStdString path = item.GetBaseMoviePath(test_files[i].use_folder);
  2322. if (path != test_files[i].base)
  2323. {
  2324. CLog::Log(LOGFATAL, "%s failed ('%s' -> '%s' != '%s')", __FUNCTION__, test_files[i].file, path.c_str(), test_files[i].base);
  2325. return false;
  2326. }
  2327. }
  2328. return true;
  2329. }
  2330. #endif
  2331. CStdString CFileItem::GetLocalFanart() const
  2332. {
  2333. if (IsVideoDb())
  2334. {
  2335. if (!HasVideoInfoTag())
  2336. return ""; // nothing can be done
  2337. CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
  2338. return dbItem.GetLocalFanart();
  2339. }
  2340. CStdString strFile2;
  2341. CStdString strFile = m_strPath;
  2342. if (IsStack())
  2343. {
  2344. CStdString strPath;
  2345. URIUtils::GetParentPath(m_strPath,strPath);
  2346. CStackDirectory dir;
  2347. CStdString strPath2;
  2348. strPath2 = dir.GetStackedTitlePath(strFile);
  2349. URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2),strFile);
  2350. CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
  2351. CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-fanart"));
  2352. URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strFile2);
  2353. }
  2354. if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
  2355. {
  2356. CStdString strPath, strParent;
  2357. URIUtils::GetDirectory(strFile,strPath);
  2358. URIUtils::GetParentPath(strPath,strParent);
  2359. URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
  2360. }
  2361. // no local fanart available for these
  2362. if (IsInternetStream()
  2363. || URIUtils::IsUPnP(strFile)
  2364. || URIUtils::IsBluray(strFile)
  2365. || IsLiveTV()
  2366. || IsPlugin()
  2367. || IsAddonsPath()
  2368. || IsDVD()
  2369. || (URIUtils::IsFTP(strFile) && !g_advancedSettings.m_bFTPThumbs)
  2370. || m_strPath.IsEmpty())
  2371. return "";
  2372. CStdString strDir;
  2373. URIUtils::GetDirectory(strFile, strDir);
  2374. if (strDir.IsEmpty())
  2375. return "";
  2376. CFileItemList items;
  2377. CDirectory::GetDirectory(strDir, items, g_settings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
  2378. if (IsOpticalMediaFile())
  2379. { // grab from the optical media parent folder as well - see GetUserVideoThumb
  2380. CFileItemList moreItems;
  2381. CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems, g_settings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
  2382. items.Append(moreItems);
  2383. }
  2384. CStdStringArray fanarts;
  2385. StringUtils::SplitString(g_advancedSettings.m_fanartImages, "|", fanarts);
  2386. strFile = URIUtils::ReplaceExtension(strFile, "-fanart");
  2387. fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile));
  2388. if (!strFile2.IsEmpty())
  2389. fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile2));
  2390. for (unsigned int i = 0; i < fanarts.size(); ++i)
  2391. {
  2392. for (int j = 0; j < items.Size(); j++)
  2393. {
  2394. CStdString strCandidate = URIUtils::GetFileName(items[j]->m_strPath);
  2395. URIUtils::RemoveExtension(strCandidate);
  2396. CStdString strFanart = fanarts[i];
  2397. URIUtils::RemoveExtension(strFanart);
  2398. if (strCandidate.CompareNoCase(strFanart) == 0)
  2399. return items[j]->m_strPath;
  2400. }
  2401. }
  2402. return "";
  2403. }
  2404. CStdString CFileItem::GetLocalMetadataPath() const
  2405. {
  2406. if (m_bIsFolder && !IsFileFolder())
  2407. return m_strPath;
  2408. CStdString parent(URIUtils::GetParentPath(m_strPath));
  2409. CStdString parentFolder(parent);
  2410. URIUtils::RemoveSlashAtEnd(parentFolder);
  2411. parentFolder = URIUtils::GetFileName(parentFolder);
  2412. if (parentFolder.CompareNoCase("VIDEO_TS") == 0 || parentFolder.CompareNoCase("BDMV") == 0)
  2413. { // go back up another one
  2414. parent = URIUtils::GetParentPath(parent);
  2415. }
  2416. return parent;
  2417. }
  2418. bool CFileItem::LoadMusicTag()
  2419. {
  2420. // not audio
  2421. if (!IsAudio())
  2422. return false;
  2423. // already loaded?
  2424. if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
  2425. return true;
  2426. // check db
  2427. CMusicDatabase musicDatabase;
  2428. if (musicDatabase.Open())
  2429. {
  2430. CSong song;
  2431. if (musicDatabase.GetSongByFileName(m_strPath, song))
  2432. {
  2433. GetMusicInfoTag()->SetSong(song);
  2434. SetThumbnailImage(song.strThumb);
  2435. return true;
  2436. }
  2437. musicDatabase.Close();
  2438. }
  2439. // load tag from file
  2440. CLog::Log(LOGDEBUG, "%s: loading tag information for file: %s", __FUNCTION__, m_strPath.c_str());
  2441. CMusicInfoTagLoaderFactory factory;
  2442. auto_ptr<IMusicInfoTagLoader> pLoader (factory.CreateLoader(m_strPath));
  2443. if (NULL != pLoader.get())
  2444. {
  2445. if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
  2446. return true;
  2447. }
  2448. // no tag - try some other things
  2449. if (IsCDDA())
  2450. {
  2451. // we have the tracknumber...
  2452. int iTrack = GetMusicInfoTag()->GetTrackNumber();
  2453. if (iTrack >= 1)
  2454. {
  2455. CStdString strText = g_localizeStrings.Get(554); // "Track"
  2456. if (strText.GetAt(strText.size() - 1) != ' ')
  2457. strText += " ";
  2458. CStdString strTrack;
  2459. strTrack.Format(strText + "%i", iTrack);
  2460. GetMusicInfoTag()->SetTitle(strTrack);
  2461. GetMusicInfoTag()->SetLoaded(true);
  2462. return true;
  2463. }
  2464. }
  2465. else
  2466. {
  2467. CStdString fileName = URIUtils::GetFileName(m_strPath);
  2468. URIUtils::RemoveExtension(fileName);
  2469. for (unsigned int i = 0; i < g_advancedSettings.m_musicTagsFromFileFilters.size(); i++)
  2470. {
  2471. CLabelFormatter formatter(g_advancedSettings.m_musicTagsFromFileFilters[i], "");
  2472. if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
  2473. {
  2474. GetMusicInfoTag()->SetLoaded(true);
  2475. return true;
  2476. }
  2477. }
  2478. }
  2479. return false;
  2480. }
  2481. void CFileItemList::Swap(unsigned int item1, unsigned int item2)
  2482. {
  2483. if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size())
  2484. std::swap(m_items[item1], m_items[item2]);
  2485. }
  2486. bool CFileItemList::UpdateItem(const CFileItem *item)
  2487. {
  2488. if (!item) return false;
  2489. CSingleLock lock(m_lock);
  2490. for (unsigned int i = 0; i < m_items.size(); i++)
  2491. {
  2492. CFileItemPtr pItem = m_items[i];
  2493. if (pItem->IsSamePath(item))
  2494. {
  2495. *pItem = *item;
  2496. return true;
  2497. }
  2498. }
  2499. return false;
  2500. }
  2501. void CFileItemList::AddSortMethod(SORT_METHOD sortMethod, int buttonLabel, const LABEL_MASKS &labelMasks)
  2502. {
  2503. SORT_METHOD_DETAILS sort;
  2504. sort.m_sortMethod=sortMethod;
  2505. sort.m_buttonLabel=buttonLabel;
  2506. sort.m_labelMasks=labelMasks;
  2507. m_sortDetails.push_back(sort);
  2508. }
  2509. void CFileItemList::SetReplaceListing(bool replace)
  2510. {
  2511. m_replaceListing = replace;
  2512. }
  2513. void CFileItemList::ClearSortState()
  2514. {
  2515. m_sortMethod = SORT_METHOD_NONE;
  2516. m_sortOrder = SortOrderNone;
  2517. }
  2518. CVideoInfoTag* CFileItem::GetVideoInfoTag()
  2519. {
  2520. if (!m_videoInfoTag)
  2521. m_videoInfoTag = new CVideoInfoTag;
  2522. return m_videoInfoTag;
  2523. }
  2524. CPictureInfoTag* CFileItem::GetPictureInfoTag()
  2525. {
  2526. if (!m_pictureInfoTag)
  2527. m_pictureInfoTag = new CPictureInfoTag;
  2528. return m_pictureInfoTag;
  2529. }
  2530. MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
  2531. {
  2532. if (!m_musicInfoTag)
  2533. m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
  2534. return m_musicInfoTag;
  2535. }
  2536. CStdString CFileItem::FindTrailer() const
  2537. {
  2538. CStdString strFile2;
  2539. CStdString strFile = m_strPath;
  2540. if (IsStack())
  2541. {
  2542. CStdString strPath;
  2543. URIUtils::GetParentPath(m_strPath,strPath);
  2544. CStackDirectory dir;
  2545. CStdString strPath2;
  2546. strPath2 = dir.GetStackedTitlePath(strFile);
  2547. URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2),strFile);
  2548. CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
  2549. CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-trailer"));
  2550. URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strFile2);
  2551. }
  2552. if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
  2553. {
  2554. CStdString strPath, strParent;
  2555. URIUtils::GetDirectory(strFile,strPath);
  2556. URIUtils::GetParentPath(strPath,strParent);
  2557. URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
  2558. }
  2559. // no local trailer available for these
  2560. if (IsInternetStream()
  2561. || URIUtils::IsUPnP(strFile)
  2562. || URIUtils::IsBluray(strFile)
  2563. || IsLiveTV()
  2564. || IsPlugin()
  2565. || IsDVD())
  2566. return "";
  2567. CStdString strDir;
  2568. URIUtils::GetDirectory(strFile, strDir);
  2569. CFileItemList items;
  2570. CDirectory::GetDirectory(strDir, items, g_settings.m_videoExtensions, DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
  2571. URIUtils::RemoveExtension(strFile);
  2572. strFile += "-trailer";
  2573. CStdString strFile3 = URIUtils::AddFileToFolder(strDir, "movie-trailer");
  2574. // Precompile our REs
  2575. VECCREGEXP matchRegExps;
  2576. CRegExp tmpRegExp(true);
  2577. const CStdStringArray& strMatchRegExps = g_advancedSettings.m_trailerMatchRegExps;
  2578. CStdStringArray::const_iterator strRegExp = strMatchRegExps.begin();
  2579. while (strRegExp != strMatchRegExps.end())
  2580. {
  2581. if (tmpRegExp.RegComp(*strRegExp))
  2582. {
  2583. matchRegExps.push_back(tmpRegExp);
  2584. }
  2585. strRegExp++;
  2586. }
  2587. CStdString strTrailer;
  2588. for (int i = 0; i < items.Size(); i++)
  2589. {
  2590. CStdString strCandidate = items[i]->m_strPath;
  2591. URIUtils::RemoveExtension(strCandidate);
  2592. if (strCandidate.CompareNoCase(strFile) == 0 ||
  2593. strCandidate.CompareNoCase(strFile2) == 0 ||
  2594. strCandidate.CompareNoCase(strFile3) == 0)
  2595. {
  2596. strTrailer = items[i]->m_strPath;
  2597. break;
  2598. }
  2599. else
  2600. {
  2601. VECCREGEXP::iterator expr = matchRegExps.begin();
  2602. while (expr != matchRegExps.end())
  2603. {
  2604. if (expr->RegFind(strCandidate) != -1)
  2605. {
  2606. strTrailer = items[i]->m_strPath;
  2607. i = items.Size();
  2608. break;
  2609. }
  2610. expr++;
  2611. }
  2612. }
  2613. }
  2614. return strTrailer;
  2615. }
  2616. int CFileItem::GetVideoContentType() const
  2617. {
  2618. VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
  2619. if (HasVideoInfoTag() && !GetVideoInfoTag()->m_strShowTitle.IsEmpty()) // tvshow
  2620. type = VIDEODB_CONTENT_TVSHOWS;
  2621. if (HasVideoInfoTag() && GetVideoInfoTag()->m_iSeason > -1 && !m_bIsFolder) // episode
  2622. type = VIDEODB_CONTENT_EPISODES;
  2623. if (HasVideoInfoTag() && !GetVideoInfoTag()->m_artist.empty())
  2624. type = VIDEODB_CONTENT_MUSICVIDEOS;
  2625. return type;
  2626. }