mirror of
https://github.com/Team-Resurgent/XBMC4Xbox.git
synced 2026-08-15 11:18:13 -07:00
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
3279 lines
85 KiB
C++
3279 lines
85 KiB
C++
/*
|
|
* Copyright (C) 2005-2013 Team XBMC
|
|
* http://xbmc.org
|
|
*
|
|
* This Program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This Program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with XBMC; see the file COPYING. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "system.h"
|
|
#include "utils/log.h"
|
|
#include "FileItem.h"
|
|
#include "Util.h"
|
|
#include "utils/URIUtils.h"
|
|
#include "pictures/Picture.h"
|
|
#include "playlists/PlayListFactory.h"
|
|
#include "Shortcut.h"
|
|
#include "utils/Crc32.h"
|
|
#include "FileSystem/DirectoryCache.h"
|
|
#include "FileSystem/StackDirectory.h"
|
|
#include "FileSystem/CurlFile.h"
|
|
#include "FileSystem/MultiPathDirectory.h"
|
|
#include "FileSystem/MusicDatabaseDirectory.h"
|
|
#include "FileSystem/VideoDatabaseDirectory.h"
|
|
#include "FileSystem/DirectoryFactory.h"
|
|
#include "music/tags/MusicInfoTagLoaderFactory.h"
|
|
#include "CueDocument.h"
|
|
#include "video/VideoDatabase.h"
|
|
#include "music/MusicDatabase.h"
|
|
#include "SortFileItem.h"
|
|
#include "utils/TuxBoxUtil.h"
|
|
#include "video/VideoInfoTag.h"
|
|
#include "utils/SingleLock.h"
|
|
#include "music/tags/MusicInfoTag.h"
|
|
#include "pictures/PictureInfoTag.h"
|
|
#include "music/Artist.h"
|
|
#include "music/Album.h"
|
|
#include "music/Song.h"
|
|
#include "URL.h"
|
|
#include "settings/Settings.h"
|
|
#include "settings/AdvancedSettings.h"
|
|
#include "LocalizeStrings.h"
|
|
#include "utils/RegExp.h"
|
|
#include "utils/Variant.h"
|
|
|
|
using namespace std;
|
|
using namespace XFILE;
|
|
using namespace PLAYLIST;
|
|
using namespace MUSIC_INFO;
|
|
|
|
CFileItem::CFileItem(const CSong& song)
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
Reset();
|
|
SetLabel(song.strTitle);
|
|
m_strPath = song.strFileName;
|
|
GetMusicInfoTag()->SetSong(song);
|
|
m_lStartOffset = song.iStartOffset;
|
|
m_lEndOffset = song.iEndOffset;
|
|
m_strThumbnailImage = song.strThumb;
|
|
}
|
|
|
|
CFileItem::CFileItem(const CStdString &path, const CAlbum& album)
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
Reset();
|
|
SetLabel(album.strAlbum);
|
|
m_strPath = path;
|
|
m_bIsFolder = true;
|
|
m_strLabel2 = album.strArtist;
|
|
URIUtils::AddSlashAtEnd(m_strPath);
|
|
GetMusicInfoTag()->SetAlbum(album);
|
|
if (album.thumbURL.m_url.size() > 0)
|
|
m_strThumbnailImage = album.thumbURL.m_url[0].m_url;
|
|
else
|
|
m_strThumbnailImage.clear();
|
|
|
|
/* TODO: remove when we remove old properties */
|
|
SetProperty("description", album.strReview);
|
|
SetProperty("theme", album.strThemes);
|
|
SetProperty("mood", album.strMoods);
|
|
SetProperty("style", album.strStyles);
|
|
SetProperty("type", album.strType);
|
|
SetProperty("label", album.strLabel);
|
|
if (album.iRating > 0)
|
|
SetProperty("rating", album.iRating);
|
|
|
|
CMusicDatabase::SetPropertiesFromAlbum(*this,album);
|
|
}
|
|
|
|
CFileItem::CFileItem(const CVideoInfoTag& movie)
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
Reset();
|
|
SetLabel(movie.m_strTitle);
|
|
if (movie.m_strFileNameAndPath.IsEmpty())
|
|
{
|
|
m_strPath = movie.m_strPath;
|
|
URIUtils::AddSlashAtEnd(m_strPath);
|
|
m_bIsFolder = true;
|
|
}
|
|
else
|
|
{
|
|
m_strPath = movie.m_strFileNameAndPath;
|
|
m_bIsFolder = false;
|
|
}
|
|
*GetVideoInfoTag() = movie;
|
|
FillInDefaultIcon();
|
|
SetCachedVideoThumb();
|
|
}
|
|
|
|
CFileItem::CFileItem(const CArtist& artist)
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
Reset();
|
|
SetLabel(artist.strArtist);
|
|
m_strPath = artist.strArtist;
|
|
m_bIsFolder = true;
|
|
URIUtils::AddSlashAtEnd(m_strPath);
|
|
GetMusicInfoTag()->SetArtist(artist.strArtist);
|
|
}
|
|
|
|
CFileItem::CFileItem(const CGenre& genre)
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
Reset();
|
|
SetLabel(genre.strGenre);
|
|
m_strPath = genre.strGenre;
|
|
m_bIsFolder = true;
|
|
URIUtils::AddSlashAtEnd(m_strPath);
|
|
GetMusicInfoTag()->SetGenre(genre.strGenre);
|
|
}
|
|
|
|
CFileItem::CFileItem(const CFileItem& item): CGUIListItem()
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
*this = item;
|
|
}
|
|
|
|
CFileItem::CFileItem(const CGUIListItem& item)
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
Reset();
|
|
// not particularly pretty, but it gets around the issue of Reset() defaulting
|
|
// parameters in the CGUIListItem base class.
|
|
*((CGUIListItem *)this) = item;
|
|
}
|
|
|
|
CFileItem::CFileItem(void)
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
Reset();
|
|
}
|
|
|
|
CFileItem::CFileItem(const CStdString& strLabel)
|
|
: CGUIListItem()
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
Reset();
|
|
SetLabel(strLabel);
|
|
}
|
|
|
|
CFileItem::CFileItem(const CStdString& strPath, bool bIsFolder)
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
Reset();
|
|
m_strPath = strPath;
|
|
m_bIsFolder = bIsFolder;
|
|
// tuxbox urls cannot have a / at end
|
|
if (m_bIsFolder && !m_strPath.IsEmpty() && !IsFileFolder() && !URIUtils::IsTuxBox(m_strPath))
|
|
{
|
|
#ifdef DEBUG
|
|
ASSERT(URIUtils::HasSlashAtEnd(m_strPath));
|
|
#endif
|
|
URIUtils::AddSlashAtEnd(m_strPath);
|
|
}
|
|
}
|
|
|
|
CFileItem::CFileItem(const CMediaSource& share)
|
|
{
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
Reset();
|
|
m_bIsFolder = true;
|
|
m_bIsShareOrDrive = true;
|
|
m_strPath = share.strPath;
|
|
URIUtils::AddSlashAtEnd(m_strPath);
|
|
CStdString label = share.strName;
|
|
if (!share.strStatus.IsEmpty())
|
|
label.Format("%s (%s)", share.strName.c_str(), share.strStatus.c_str());
|
|
SetLabel(label);
|
|
m_iLockMode = share.m_iLockMode;
|
|
m_strLockCode = share.m_strLockCode;
|
|
m_iHasLock = share.m_iHasLock;
|
|
m_iBadPwdCount = share.m_iBadPwdCount;
|
|
m_iDriveType = share.m_iDriveType;
|
|
m_strThumbnailImage = share.m_strThumbnailImage;
|
|
SetLabelPreformated(true);
|
|
}
|
|
|
|
CFileItem::~CFileItem(void)
|
|
{
|
|
delete m_musicInfoTag;
|
|
delete m_videoInfoTag;
|
|
delete m_pictureInfoTag;
|
|
|
|
m_musicInfoTag = NULL;
|
|
m_videoInfoTag = NULL;
|
|
m_pictureInfoTag = NULL;
|
|
}
|
|
|
|
const CFileItem& CFileItem::operator=(const CFileItem& item)
|
|
{
|
|
if (this == &item) return * this;
|
|
CGUIListItem::operator=(item);
|
|
m_bLabelPreformated=item.m_bLabelPreformated;
|
|
FreeMemory();
|
|
m_strPath = item.GetPath();
|
|
m_bIsParentFolder = item.m_bIsParentFolder;
|
|
m_iDriveType = item.m_iDriveType;
|
|
m_bIsShareOrDrive = item.m_bIsShareOrDrive;
|
|
m_dateTime = item.m_dateTime;
|
|
m_dwSize = item.m_dwSize;
|
|
if (item.HasMusicInfoTag())
|
|
{
|
|
m_musicInfoTag = GetMusicInfoTag();
|
|
if (m_musicInfoTag)
|
|
*m_musicInfoTag = *item.m_musicInfoTag;
|
|
}
|
|
else
|
|
{
|
|
delete m_musicInfoTag;
|
|
m_musicInfoTag = NULL;
|
|
}
|
|
|
|
if (item.HasVideoInfoTag())
|
|
{
|
|
m_videoInfoTag = GetVideoInfoTag();
|
|
if (m_videoInfoTag)
|
|
*m_videoInfoTag = *item.m_videoInfoTag;
|
|
}
|
|
else
|
|
{
|
|
delete m_videoInfoTag;
|
|
m_videoInfoTag = NULL;
|
|
}
|
|
|
|
if (item.HasPictureInfoTag())
|
|
{
|
|
m_pictureInfoTag = GetPictureInfoTag();
|
|
if (m_pictureInfoTag)
|
|
*m_pictureInfoTag = *item.m_pictureInfoTag;
|
|
}
|
|
else
|
|
{
|
|
delete m_pictureInfoTag;
|
|
m_pictureInfoTag = NULL;
|
|
}
|
|
|
|
m_lStartOffset = item.m_lStartOffset;
|
|
m_lEndOffset = item.m_lEndOffset;
|
|
m_strDVDLabel = item.m_strDVDLabel;
|
|
m_strTitle = item.m_strTitle;
|
|
m_iprogramCount = item.m_iprogramCount;
|
|
m_idepth = item.m_idepth;
|
|
m_iLockMode = item.m_iLockMode;
|
|
m_strLockCode = item.m_strLockCode;
|
|
m_iHasLock = item.m_iHasLock;
|
|
m_iBadPwdCount = item.m_iBadPwdCount;
|
|
m_bCanQueue=item.m_bCanQueue;
|
|
m_mimetype = item.m_mimetype;
|
|
m_extrainfo = item.m_extrainfo;
|
|
m_specialSort = item.m_specialSort;
|
|
return *this;
|
|
}
|
|
|
|
void CFileItem::Reset()
|
|
{
|
|
m_strLabel2.Empty();
|
|
SetLabel("");
|
|
m_bLabelPreformated=false;
|
|
FreeIcons();
|
|
m_overlayIcon = ICON_OVERLAY_NONE;
|
|
m_bSelected = false;
|
|
m_strDVDLabel.Empty();
|
|
m_strTitle.Empty();
|
|
m_strPath.Empty();
|
|
m_dwSize = 0;
|
|
m_bIsFolder = false;
|
|
m_bIsParentFolder=false;
|
|
m_bIsShareOrDrive = false;
|
|
m_dateTime.Reset();
|
|
m_iDriveType = CMediaSource::SOURCE_TYPE_UNKNOWN;
|
|
m_lStartOffset = 0;
|
|
m_lEndOffset = 0;
|
|
m_iprogramCount = 0;
|
|
m_idepth = 1;
|
|
m_iLockMode = LOCK_MODE_EVERYONE;
|
|
m_strLockCode = "";
|
|
m_iBadPwdCount = 0;
|
|
m_iHasLock = 0;
|
|
m_bCanQueue=true;
|
|
m_mimetype = "";
|
|
delete m_musicInfoTag;
|
|
m_musicInfoTag=NULL;
|
|
delete m_videoInfoTag;
|
|
m_videoInfoTag=NULL;
|
|
delete m_pictureInfoTag;
|
|
m_pictureInfoTag=NULL;
|
|
m_extrainfo.Empty();
|
|
m_specialSort = SORT_NORMALLY;
|
|
SetInvalid();
|
|
}
|
|
|
|
void CFileItem::Archive(CArchive& ar)
|
|
{
|
|
CGUIListItem::Archive(ar);
|
|
|
|
if (ar.IsStoring())
|
|
{
|
|
ar << m_bIsParentFolder;
|
|
ar << m_bLabelPreformated;
|
|
ar << m_strPath;
|
|
ar << m_bIsShareOrDrive;
|
|
ar << m_iDriveType;
|
|
ar << m_dateTime;
|
|
ar << m_dwSize;
|
|
ar << m_strDVDLabel;
|
|
ar << m_strTitle;
|
|
ar << m_iprogramCount;
|
|
ar << m_idepth;
|
|
ar << m_lStartOffset;
|
|
ar << m_lEndOffset;
|
|
ar << m_iLockMode;
|
|
ar << m_strLockCode;
|
|
ar << m_iBadPwdCount;
|
|
|
|
ar << m_bCanQueue;
|
|
ar << m_mimetype;
|
|
ar << m_extrainfo;
|
|
ar << m_specialSort;
|
|
|
|
if (m_musicInfoTag)
|
|
{
|
|
ar << 1;
|
|
ar << *m_musicInfoTag;
|
|
}
|
|
else
|
|
ar << 0;
|
|
if (m_videoInfoTag)
|
|
{
|
|
ar << 1;
|
|
ar << *m_videoInfoTag;
|
|
}
|
|
else
|
|
ar << 0;
|
|
if (m_pictureInfoTag)
|
|
{
|
|
ar << 1;
|
|
ar << *m_pictureInfoTag;
|
|
}
|
|
else
|
|
ar << 0;
|
|
}
|
|
else
|
|
{
|
|
ar >> m_bIsParentFolder;
|
|
ar >> m_bLabelPreformated;
|
|
ar >> m_strPath;
|
|
ar >> m_bIsShareOrDrive;
|
|
ar >> m_iDriveType;
|
|
ar >> m_dateTime;
|
|
ar >> m_dwSize;
|
|
ar >> m_strDVDLabel;
|
|
ar >> m_strTitle;
|
|
ar >> m_iprogramCount;
|
|
ar >> m_idepth;
|
|
ar >> m_lStartOffset;
|
|
ar >> m_lEndOffset;
|
|
int temp;
|
|
ar >> temp;
|
|
m_iLockMode = (LockType)temp;
|
|
ar >> m_strLockCode;
|
|
ar >> m_iBadPwdCount;
|
|
|
|
ar >> m_bCanQueue;
|
|
ar >> m_mimetype;
|
|
ar >> m_extrainfo;
|
|
ar >> temp;
|
|
m_specialSort = (SPECIAL_SORT)temp;
|
|
|
|
int iType;
|
|
ar >> iType;
|
|
if (iType == 1)
|
|
ar >> *GetMusicInfoTag();
|
|
ar >> iType;
|
|
if (iType == 1)
|
|
ar >> *GetVideoInfoTag();
|
|
ar >> iType;
|
|
if (iType == 1)
|
|
ar >> *GetPictureInfoTag();
|
|
|
|
SetInvalid();
|
|
}
|
|
}
|
|
void CFileItem::Serialize(CVariant& value)
|
|
{
|
|
//CGUIListItem::Serialize(value["CGUIListItem"]);
|
|
|
|
value["strPath"] = m_strPath;
|
|
value["dateTime"] = (m_dateTime.IsValid()) ? m_dateTime.GetAsRFC1123DateTime() : "";
|
|
value["size"] = (int) m_dwSize / 1000;
|
|
value["DVDLabel"] = m_strDVDLabel;
|
|
value["title"] = m_strTitle;
|
|
value["mimetype"] = m_mimetype;
|
|
value["extrainfo"] = m_extrainfo;
|
|
|
|
if (m_musicInfoTag)
|
|
(*m_musicInfoTag).Serialize(value["musicInfoTag"]);
|
|
|
|
if (m_videoInfoTag)
|
|
(*m_videoInfoTag).Serialize(value["videoInfoTag"]);
|
|
|
|
if (m_pictureInfoTag)
|
|
(*m_pictureInfoTag).Serialize(value["pictureInfoTag"]);
|
|
}
|
|
bool CFileItem::Exists(bool bUseCache /* = true */) const
|
|
{
|
|
if (m_strPath.IsEmpty()
|
|
|| m_strPath.Equals("add")
|
|
|| IsInternetStream()
|
|
|| IsParentFolder()
|
|
|| IsVirtualDirectoryRoot()
|
|
|| IsPlugin())
|
|
return true;
|
|
|
|
if (IsVideoDb() && HasVideoInfoTag())
|
|
{
|
|
CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
|
|
return dbItem.Exists();
|
|
}
|
|
|
|
CStdString strPath = m_strPath;
|
|
|
|
if (URIUtils::IsMultiPath(strPath))
|
|
strPath = CMultiPathDirectory::GetFirstPath(strPath);
|
|
|
|
if (URIUtils::IsStack(strPath))
|
|
strPath = CStackDirectory::GetFirstStackedFile(strPath);
|
|
|
|
if (m_bIsFolder)
|
|
return CDirectory::Exists(strPath);
|
|
else
|
|
return CFile::Exists(strPath, bUseCache);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CFileItem::IsVideo() const
|
|
{
|
|
/* check preset mime type */
|
|
if( m_mimetype.Left(6).Equals("video/") )
|
|
return true;
|
|
|
|
if (HasVideoInfoTag()) return true;
|
|
if (HasMusicInfoTag()) return false;
|
|
if (HasPictureInfoTag()) return false;
|
|
|
|
if (IsHDHomeRun() || IsTuxBox() || URIUtils::IsDVD(m_strPath) || IsSlingbox())
|
|
return true;
|
|
|
|
CStdString extension;
|
|
if( m_mimetype.Left(12).Equals("application/") )
|
|
{ /* check for some standard types */
|
|
extension = m_mimetype.Mid(12);
|
|
if( extension.Equals("ogg")
|
|
|| extension.Equals("mp4")
|
|
|| extension.Equals("mxf") )
|
|
return true;
|
|
}
|
|
|
|
URIUtils::GetExtension(m_strPath, extension);
|
|
|
|
if (extension.IsEmpty())
|
|
return false;
|
|
|
|
extension.ToLower();
|
|
|
|
if (g_settings.m_videoExtensions.Find(extension) != -1)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CFileItem::IsAudio() const
|
|
{
|
|
/* check preset mime type */
|
|
if( m_mimetype.Left(6).Equals("audio/") )
|
|
return true;
|
|
|
|
if (HasMusicInfoTag()) return true;
|
|
if (HasVideoInfoTag()) return false;
|
|
if (HasPictureInfoTag()) return false;
|
|
if (IsCDDA()) return true;
|
|
if (!m_bIsFolder && IsShoutCast()) return true;
|
|
if (!m_bIsFolder && IsLastFM()) return true;
|
|
|
|
CStdString extension;
|
|
if( m_mimetype.Left(12).Equals("application/") )
|
|
{ /* check for some standard types */
|
|
extension = m_mimetype.Mid(12);
|
|
if( extension.Equals("ogg")
|
|
|| extension.Equals("mp4")
|
|
|| extension.Equals("mxf") )
|
|
return true;
|
|
}
|
|
|
|
URIUtils::GetExtension(m_strPath, extension);
|
|
|
|
if (extension.IsEmpty())
|
|
return false;
|
|
|
|
extension.ToLower();
|
|
if (g_settings.m_musicExtensions.Find(extension) != -1)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CFileItem::IsPicture() const
|
|
{
|
|
if( m_mimetype.Left(6).Equals("image/") )
|
|
return true;
|
|
|
|
if (HasPictureInfoTag()) return true;
|
|
if (HasMusicInfoTag()) return false;
|
|
if (HasVideoInfoTag()) return false;
|
|
|
|
return CUtil::IsPicture(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsLyrics() const
|
|
{
|
|
return URIUtils::GetExtension(m_strPath).Equals(".cdg", false) || URIUtils::GetExtension(m_strPath).Equals(".lrc", false);
|
|
}
|
|
|
|
bool CFileItem::IsCUESheet() const
|
|
{
|
|
return URIUtils::GetExtension(m_strPath).Equals(".cue", false);
|
|
}
|
|
|
|
bool CFileItem::IsShoutCast() const
|
|
{
|
|
return URIUtils::IsShoutCast(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsLastFM() const
|
|
{
|
|
return URIUtils::IsLastFM(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsInternetStream() const
|
|
{
|
|
if (HasProperty("IsHTTPDirectory"))
|
|
return false;
|
|
|
|
return URIUtils::IsInternetStream(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsFileFolder() const
|
|
{
|
|
return (
|
|
IsSmartPlayList() ||
|
|
(IsPlayList() && g_advancedSettings.m_playlistAsFolders) ||
|
|
IsZIP() ||
|
|
IsRAR() ||
|
|
IsRSS() ||
|
|
IsType(".ogg") ||
|
|
IsType(".nsf") ||
|
|
IsType(".sid") ||
|
|
IsType(".sap") ||
|
|
IsShoutCast()
|
|
);
|
|
}
|
|
|
|
|
|
bool CFileItem::IsSmartPlayList() const
|
|
{
|
|
CStdString strExtension;
|
|
URIUtils::GetExtension(m_strPath, strExtension);
|
|
strExtension.ToLower();
|
|
return (strExtension == ".xsp");
|
|
}
|
|
|
|
bool CFileItem::IsPlayList() const
|
|
{
|
|
return CPlayListFactory::IsPlaylist(*this);
|
|
}
|
|
|
|
bool CFileItem::IsPythonScript() const
|
|
{
|
|
return URIUtils::GetExtension(m_strPath).Equals(".py", false);
|
|
}
|
|
|
|
bool CFileItem::IsXBE() const
|
|
{
|
|
return URIUtils::GetExtension(m_strPath).Equals(".xbe", false);
|
|
}
|
|
|
|
bool CFileItem::IsType(const char *ext) const
|
|
{
|
|
return URIUtils::GetExtension(m_strPath).Equals(ext, false);
|
|
}
|
|
|
|
bool CFileItem::IsDefaultXBE() const
|
|
{
|
|
CStdString filename = URIUtils::GetFileName(m_strPath);
|
|
if (filename.Equals("default.xbe")) return true;
|
|
return false;
|
|
}
|
|
|
|
bool CFileItem::IsShortCut() const
|
|
{
|
|
return URIUtils::GetExtension(m_strPath).Equals(".cut", false);
|
|
}
|
|
|
|
bool CFileItem::IsNFO() const
|
|
{
|
|
return URIUtils::GetExtension(m_strPath).Equals(".nfo", false);
|
|
}
|
|
|
|
bool CFileItem::IsDVDImage() const
|
|
{
|
|
CStdString strExtension;
|
|
URIUtils::GetExtension(m_strPath, strExtension);
|
|
if (strExtension.Equals(".img") || strExtension.Equals(".iso") || strExtension.Equals(".nrg")) return true;
|
|
return false;
|
|
}
|
|
|
|
bool CFileItem::IsDVDFile(bool bVobs /*= true*/, bool bIfos /*= true*/) const
|
|
{
|
|
CStdString strFileName = URIUtils::GetFileName(m_strPath);
|
|
if (bIfos)
|
|
{
|
|
if (strFileName.Equals("video_ts.ifo")) return true;
|
|
if (strFileName.Left(4).Equals("vts_") && strFileName.Right(6).Equals("_0.ifo") && strFileName.length() == 12) return true;
|
|
}
|
|
if (bVobs)
|
|
{
|
|
if (strFileName.Equals("video_ts.vob")) return true;
|
|
if (strFileName.Left(4).Equals("vts_") && strFileName.Right(4).Equals(".vob")) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CFileItem::IsRAR() const
|
|
{
|
|
return URIUtils::IsRAR(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsZIP() const
|
|
{
|
|
return URIUtils::IsZIP(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsCBZ() const
|
|
{
|
|
return URIUtils::GetExtension(m_strPath).Equals(".cbz", false);
|
|
}
|
|
|
|
bool CFileItem::IsCBR() const
|
|
{
|
|
return URIUtils::GetExtension(m_strPath).Equals(".cbr", false);
|
|
}
|
|
|
|
bool CFileItem::IsRSS() const
|
|
{
|
|
if (m_strPath.Left(6).Equals("rss://"))
|
|
return true;
|
|
|
|
return URIUtils::GetExtension(m_strPath).Equals(".rss")
|
|
|| GetMimeType() == "application/rss+xml";
|
|
}
|
|
|
|
bool CFileItem::IsStack() const
|
|
{
|
|
return URIUtils::IsStack(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsPlugin() const
|
|
{
|
|
return URIUtils::IsPlugin(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsPluginRoot() const
|
|
{
|
|
return URIUtils::IsPluginRoot(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsMultiPath() const
|
|
{
|
|
return URIUtils::IsMultiPath(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsCDDA() const
|
|
{
|
|
return URIUtils::IsCDDA(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsDVD() const
|
|
{
|
|
return URIUtils::IsDVD(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsOnDVD() const
|
|
{
|
|
return URIUtils::IsOnDVD(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsOnLAN() const
|
|
{
|
|
return URIUtils::IsOnLAN(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsISO9660() const
|
|
{
|
|
return URIUtils::IsISO9660(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsRemote() const
|
|
{
|
|
return URIUtils::IsRemote(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsSmb() const
|
|
{
|
|
return URIUtils::IsSmb(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsXBMS() const
|
|
{
|
|
return URIUtils::IsXBMS(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsURL() const
|
|
{
|
|
return URIUtils::IsURL(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsDAAP() const
|
|
{
|
|
return URIUtils::IsDAAP(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsTuxBox() const
|
|
{
|
|
return URIUtils::IsTuxBox(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsMythTV() const
|
|
{
|
|
return URIUtils::IsMythTV(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsHDHomeRun() const
|
|
{
|
|
return URIUtils::IsHDHomeRun(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsSlingbox() const
|
|
{
|
|
return URIUtils::IsSlingbox(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsVTP() const
|
|
{
|
|
return URIUtils::IsVTP(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsLiveTV() const
|
|
{
|
|
return URIUtils::IsLiveTV(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsHD() const
|
|
{
|
|
return URIUtils::IsHD(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::IsMusicDb() const
|
|
{
|
|
CURL url(m_strPath);
|
|
return url.GetProtocol().Equals("musicdb");
|
|
}
|
|
|
|
bool CFileItem::IsVideoDb() const
|
|
{
|
|
CURL url(m_strPath);
|
|
return url.GetProtocol().Equals("videodb");
|
|
}
|
|
|
|
bool CFileItem::IsVirtualDirectoryRoot() const
|
|
{
|
|
return (m_bIsFolder && m_strPath.IsEmpty());
|
|
}
|
|
|
|
bool CFileItem::IsMemoryUnit() const
|
|
{
|
|
CURL url(m_strPath);
|
|
return url.GetProtocol().Left(3).Equals("mem");
|
|
}
|
|
|
|
bool CFileItem::IsRemovable() const
|
|
{
|
|
return IsOnDVD() || IsCDDA() || IsMemoryUnit();
|
|
}
|
|
|
|
bool CFileItem::IsReadOnly() const
|
|
{
|
|
if (IsParentFolder()) return true;
|
|
if (m_bIsShareOrDrive) return true;
|
|
return !CUtil::SupportsWriteFileOperations(m_strPath);
|
|
}
|
|
|
|
void CFileItem::FillInDefaultIcon()
|
|
{
|
|
//CLog::Log(LOGINFO, "FillInDefaultIcon(%s)", pItem->GetLabel().c_str());
|
|
// find the default icon for a file or folder item
|
|
// for files this can be the (depending on the file type)
|
|
// default picture for photo's
|
|
// default picture for songs
|
|
// default picture for videos
|
|
// default picture for shortcuts
|
|
// default picture for playlists
|
|
// or the icon embedded in an .xbe
|
|
//
|
|
// for folders
|
|
// for .. folders the default picture for parent folder
|
|
// for other folders the defaultFolder.png
|
|
|
|
if (GetIconImage().IsEmpty())
|
|
{
|
|
if (!m_bIsFolder)
|
|
{
|
|
/* To reduce the average runtime of this code, this list should
|
|
* be ordered with most frequently seen types first. Also bear
|
|
* in mind the complexity of the code behind the check in the
|
|
* case of IsWhatater() returns false.
|
|
*/
|
|
if ( IsAudio() )
|
|
{
|
|
// audio
|
|
SetIconImage("DefaultAudio.png");
|
|
}
|
|
else if ( IsVideo() )
|
|
{
|
|
// video
|
|
SetIconImage("DefaultVideo.png");
|
|
}
|
|
else if ( IsPicture() )
|
|
{
|
|
// picture
|
|
SetIconImage("DefaultPicture.png");
|
|
}
|
|
else if ( IsPlayList() )
|
|
{
|
|
SetIconImage("DefaultPlaylist.png");
|
|
}
|
|
else if ( IsXBE() )
|
|
{
|
|
// xbe
|
|
SetIconImage("DefaultProgram.png");
|
|
}
|
|
else if ( IsShortCut() && !IsLabelPreformated() )
|
|
{
|
|
// shortcut
|
|
CStdString strFName = URIUtils::GetFileName(m_strPath);
|
|
int iPos = strFName.ReverseFind(".");
|
|
CStdString strDescription = strFName.Left(iPos);
|
|
SetLabel(strDescription);
|
|
SetIconImage("DefaultShortcut.png");
|
|
}
|
|
else if ( IsPythonScript() )
|
|
{
|
|
SetIconImage("DefaultScript.png");
|
|
}
|
|
else
|
|
{
|
|
// default icon for unknown file type
|
|
SetIconImage("DefaultFile.png");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( IsPlayList() )
|
|
{
|
|
SetIconImage("DefaultPlaylist.png");
|
|
}
|
|
else if (IsParentFolder())
|
|
{
|
|
SetIconImage("DefaultFolderBack.png");
|
|
}
|
|
else
|
|
{
|
|
SetIconImage("DefaultFolder.png");
|
|
}
|
|
}
|
|
}
|
|
// Set the icon overlays (if applicable)
|
|
if (!HasOverlay())
|
|
{
|
|
if (URIUtils::IsInRAR(m_strPath))
|
|
SetOverlayImage(CGUIListItem::ICON_OVERLAY_RAR);
|
|
else if (URIUtils::IsInZIP(m_strPath))
|
|
SetOverlayImage(CGUIListItem::ICON_OVERLAY_ZIP);
|
|
}
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedArtistThumb() const
|
|
{
|
|
return GetCachedThumb("artist"+GetLabel(),g_settings.GetMusicArtistThumbFolder());
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedProfileThumb() const
|
|
{
|
|
return GetCachedThumb("profile"+m_strPath,URIUtils::AddFileToFolder(g_settings.GetUserDataFolder(),"Thumbnails\\Profiles"));
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedSeasonThumb() const
|
|
{
|
|
CStdString seasonPath;
|
|
if (HasVideoInfoTag())
|
|
seasonPath = GetVideoInfoTag()->m_strPath;
|
|
|
|
return GetCachedThumb("season"+seasonPath+GetLabel(),g_settings.GetVideoThumbFolder(),true);
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedActorThumb() const
|
|
{
|
|
return GetCachedThumb("actor"+GetLabel(),g_settings.GetVideoThumbFolder(),true);
|
|
}
|
|
|
|
void CFileItem::SetCachedArtistThumb()
|
|
{
|
|
CStdString thumb(GetCachedArtistThumb());
|
|
if (CFile::Exists(thumb))
|
|
{
|
|
// found it, we are finished.
|
|
SetThumbnailImage(thumb);
|
|
}
|
|
}
|
|
|
|
// set the album thumb for a file or folder
|
|
void CFileItem::SetMusicThumb(bool alwaysCheckRemote /* = true */)
|
|
{
|
|
if (HasThumbnail()) return;
|
|
|
|
SetCachedMusicThumb();
|
|
if (!HasThumbnail())
|
|
SetUserMusicThumb(alwaysCheckRemote);
|
|
}
|
|
|
|
void CFileItem::SetCachedSeasonThumb()
|
|
{
|
|
CStdString thumb(GetCachedSeasonThumb());
|
|
if (CFile::Exists(thumb))
|
|
{
|
|
// found it, we are finished.
|
|
SetThumbnailImage(thumb);
|
|
}
|
|
}
|
|
|
|
void CFileItem::RemoveExtension()
|
|
{
|
|
if (m_bIsFolder)
|
|
return;
|
|
CStdString strLabel = GetLabel();
|
|
URIUtils::RemoveExtension(strLabel);
|
|
SetLabel(strLabel);
|
|
}
|
|
|
|
void CFileItem::CleanString()
|
|
{
|
|
if (IsLiveTV())
|
|
return;
|
|
|
|
bool bIsFolder = m_bIsFolder;
|
|
|
|
// make sure we don't append the extension to stacked dvd folders
|
|
if (HasProperty("isstacked") && IsDVDFile(false, true))
|
|
bIsFolder = true;
|
|
|
|
CStdString strLabel = GetLabel();
|
|
CStdString strTitle, strTitleAndYear, strYear;
|
|
CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, (bIsFolder || !g_guiSettings.GetBool("filelists.showextensions") ) );
|
|
SetLabel(strTitleAndYear);
|
|
}
|
|
|
|
void CFileItem::SetLabel(const CStdString &strLabel)
|
|
{
|
|
if (strLabel=="..")
|
|
{
|
|
m_bIsParentFolder=true;
|
|
m_bIsFolder=true;
|
|
m_specialSort = SORT_ON_TOP;
|
|
SetLabelPreformated(true);
|
|
}
|
|
CGUIListItem::SetLabel(strLabel);
|
|
}
|
|
|
|
void CFileItem::SetFileSizeLabel()
|
|
{
|
|
if( m_bIsFolder && m_dwSize == 0 )
|
|
SetLabel2("");
|
|
else
|
|
SetLabel2(StringUtils::SizeToString(m_dwSize));
|
|
}
|
|
|
|
CURL CFileItem::GetAsUrl() const
|
|
{
|
|
return CURL(m_strPath);
|
|
}
|
|
|
|
bool CFileItem::CanQueue() const
|
|
{
|
|
return m_bCanQueue;
|
|
}
|
|
|
|
void CFileItem::SetCanQueue(bool bYesNo)
|
|
{
|
|
m_bCanQueue=bYesNo;
|
|
}
|
|
|
|
bool CFileItem::IsParentFolder() const
|
|
{
|
|
return m_bIsParentFolder;
|
|
}
|
|
|
|
const CStdString& CFileItem::GetMimeType(bool lookup /*= true*/) const
|
|
{
|
|
if( m_mimetype.IsEmpty() && lookup)
|
|
{
|
|
// discard const qualifyier
|
|
CStdString& m_ref = (CStdString&)m_mimetype;
|
|
|
|
if( m_bIsFolder )
|
|
m_ref = "x-directory/normal";
|
|
else if( m_strPath.Left(8).Equals("shout://")
|
|
|| m_strPath.Left(7).Equals("http://")
|
|
|| m_strPath.Left(8).Equals("https://"))
|
|
{
|
|
CCurlFile::GetMimeType(GetAsUrl(), m_ref);
|
|
|
|
// try to get mime-type again but with an NSPlayer User-Agent
|
|
// in order for server to provide correct mime-type. Allows us
|
|
// to properly detect an MMS stream
|
|
if (m_ref.Left(11).Equals("video/x-ms-"))
|
|
CCurlFile::GetMimeType(GetAsUrl(), m_ref, "NSPlayer/11.00.6001.7000");
|
|
|
|
// make sure there are no options set in mime-type
|
|
// mime-type can look like "video/x-ms-asf ; charset=utf8"
|
|
int i = m_ref.Find(';');
|
|
if(i>=0)
|
|
m_ref.Delete(i,m_ref.length()-i);
|
|
m_ref.Trim();
|
|
}
|
|
|
|
// if it's still empty set to an unknown type
|
|
if( m_ref.IsEmpty() )
|
|
m_ref = "application/octet-stream";
|
|
}
|
|
|
|
// change protocol to mms for the following mome-type. Allows us to create proper FileMMS.
|
|
if( m_mimetype.Left(32).Equals("application/vnd.ms.wms-hdr.asfv1") || m_mimetype.Left(24).Equals("application/x-mms-framed") )
|
|
{
|
|
CStdString& m_path = (CStdString&)m_strPath;
|
|
m_path.Replace("http:", "mms:");
|
|
}
|
|
|
|
return m_mimetype;
|
|
}
|
|
|
|
bool CFileItem::IsSamePath(const CFileItem *item) const
|
|
{
|
|
if (!item)
|
|
return false;
|
|
|
|
if (item->GetPath() == m_strPath && item->m_lStartOffset == m_lStartOffset) return true;
|
|
if (IsMusicDb() && HasMusicInfoTag())
|
|
{
|
|
CFileItem dbItem(m_musicInfoTag->GetURL(), false);
|
|
dbItem.m_lStartOffset = m_lStartOffset;
|
|
return dbItem.IsSamePath(item);
|
|
}
|
|
if (IsVideoDb() && HasVideoInfoTag())
|
|
{
|
|
CFileItem dbItem(m_videoInfoTag->m_strFileNameAndPath, false);
|
|
dbItem.m_lStartOffset = m_lStartOffset;
|
|
return dbItem.IsSamePath(item);
|
|
}
|
|
if (item->IsMusicDb() && item->HasMusicInfoTag())
|
|
{
|
|
CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
|
|
dbItem.m_lStartOffset = item->m_lStartOffset;
|
|
return IsSamePath(&dbItem);
|
|
}
|
|
if (item->IsVideoDb() && item->HasVideoInfoTag())
|
|
{
|
|
CFileItem dbItem(item->m_videoInfoTag->m_strFileNameAndPath, false);
|
|
dbItem.m_lStartOffset = item->m_lStartOffset;
|
|
return IsSamePath(&dbItem);
|
|
}
|
|
if (HasProperty("original_listitem_url"))
|
|
return (GetProperty("original_listitem_url") == item->GetPath());
|
|
return false;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
/////
|
|
///// CFileItemList
|
|
/////
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CFileItemList::CFileItemList()
|
|
{
|
|
m_fastLookup = false;
|
|
m_bIsFolder=true;
|
|
m_cacheToDisc=CACHE_IF_SLOW;
|
|
m_sortMethod=SORT_METHOD_NONE;
|
|
m_sortOrder=SORT_ORDER_NONE;
|
|
m_replaceListing = false;
|
|
}
|
|
|
|
CFileItemList::CFileItemList(const CStdString& strPath) : CFileItem(strPath, true)
|
|
{
|
|
m_fastLookup = false;
|
|
m_cacheToDisc=CACHE_IF_SLOW;
|
|
m_sortMethod=SORT_METHOD_NONE;
|
|
m_sortOrder=SORT_ORDER_NONE;
|
|
m_replaceListing = false;
|
|
}
|
|
|
|
CFileItemList::~CFileItemList()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
CFileItemPtr CFileItemList::operator[] (int iItem)
|
|
{
|
|
return Get(iItem);
|
|
}
|
|
|
|
const CFileItemPtr CFileItemList::operator[] (int iItem) const
|
|
{
|
|
return Get(iItem);
|
|
}
|
|
|
|
CFileItemPtr CFileItemList::operator[] (const CStdString& strPath)
|
|
{
|
|
return Get(strPath);
|
|
}
|
|
|
|
const CFileItemPtr CFileItemList::operator[] (const CStdString& strPath) const
|
|
{
|
|
return Get(strPath);
|
|
}
|
|
|
|
void CFileItemList::SetFastLookup(bool fastLookup)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
if (fastLookup && !m_fastLookup)
|
|
{ // generate the map
|
|
m_map.clear();
|
|
for (unsigned int i=0; i < m_items.size(); i++)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
CStdString path(pItem->GetPath());
|
|
path.ToLower();
|
|
m_map.insert(MAPFILEITEMSPAIR(path, pItem));
|
|
}
|
|
}
|
|
if (!fastLookup && m_fastLookup)
|
|
m_map.clear();
|
|
m_fastLookup = fastLookup;
|
|
}
|
|
|
|
bool CFileItemList::Contains(const CStdString& fileName) const
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
// checks case insensitive
|
|
CStdString checkPath(fileName);
|
|
checkPath.ToLower();
|
|
if (m_fastLookup)
|
|
return m_map.find(checkPath) != m_map.end();
|
|
// slow method...
|
|
for (unsigned int i = 0; i < m_items.size(); i++)
|
|
{
|
|
const CFileItemPtr pItem = m_items[i];
|
|
if (pItem->GetPath().Equals(checkPath))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CFileItemList::Clear()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
ClearItems();
|
|
m_sortMethod=SORT_METHOD_NONE;
|
|
m_sortOrder=SORT_ORDER_NONE;
|
|
m_cacheToDisc=CACHE_IF_SLOW;
|
|
m_sortDetails.clear();
|
|
m_replaceListing = false;
|
|
m_content.Empty();
|
|
}
|
|
|
|
void CFileItemList::ClearItems()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
// make sure we free the memory of the items (these are GUIControls which may have allocated resources)
|
|
FreeMemory();
|
|
for (unsigned int i = 0; i < m_items.size(); i++)
|
|
{
|
|
CFileItemPtr item = m_items[i];
|
|
item->FreeMemory();
|
|
}
|
|
m_items.clear();
|
|
m_map.clear();
|
|
}
|
|
|
|
void CFileItemList::Add(const CFileItemPtr &pItem)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
m_items.push_back(pItem);
|
|
if (m_fastLookup)
|
|
{
|
|
CStdString path(pItem->GetPath());
|
|
path.ToLower();
|
|
m_map.insert(MAPFILEITEMSPAIR(path, pItem));
|
|
}
|
|
}
|
|
|
|
void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
if (itemPosition >= 0)
|
|
{
|
|
m_items.insert(m_items.begin()+itemPosition, pItem);
|
|
}
|
|
else
|
|
{
|
|
m_items.insert(m_items.begin()+(m_items.size()+itemPosition), pItem);
|
|
}
|
|
if (m_fastLookup)
|
|
{
|
|
CStdString path(pItem->GetPath());
|
|
path.ToLower();
|
|
m_map.insert(MAPFILEITEMSPAIR(path, pItem));
|
|
}
|
|
}
|
|
|
|
void CFileItemList::Remove(CFileItem* pItem)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it)
|
|
{
|
|
if (pItem == it->get())
|
|
{
|
|
m_items.erase(it);
|
|
if (m_fastLookup)
|
|
{
|
|
CStdString path(pItem->GetPath());
|
|
path.ToLower();
|
|
m_map.erase(path);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CFileItemList::Remove(int iItem)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
if (iItem >= 0 && iItem < (int)Size())
|
|
{
|
|
CFileItemPtr pItem = *(m_items.begin() + iItem);
|
|
if (m_fastLookup)
|
|
{
|
|
CStdString path(pItem->GetPath());
|
|
path.ToLower();
|
|
m_map.erase(path);
|
|
}
|
|
m_items.erase(m_items.begin() + iItem);
|
|
}
|
|
}
|
|
|
|
void CFileItemList::Append(const CFileItemList& itemlist)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
for (int i = 0; i < itemlist.Size(); ++i)
|
|
Add(itemlist[i]);
|
|
}
|
|
|
|
void CFileItemList::Assign(const CFileItemList& itemlist, bool append)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
if (!append)
|
|
Clear();
|
|
Append(itemlist);
|
|
SetPath(itemlist.GetPath());
|
|
m_sortDetails = itemlist.m_sortDetails;
|
|
m_replaceListing = itemlist.m_replaceListing;
|
|
m_content = itemlist.m_content;
|
|
m_mapProperties = itemlist.m_mapProperties;
|
|
m_cacheToDisc = itemlist.m_cacheToDisc;
|
|
}
|
|
|
|
bool CFileItemList::Copy(const CFileItemList& items)
|
|
{
|
|
// assign all CFileItem parts
|
|
*(CFileItem*)this = *(CFileItem*)&items;
|
|
|
|
// assign the rest of the CFileItemList properties
|
|
m_replaceListing = items.m_replaceListing;
|
|
m_content = items.m_content;
|
|
m_mapProperties = items.m_mapProperties;
|
|
m_cacheToDisc = items.m_cacheToDisc;
|
|
m_sortDetails = items.m_sortDetails;
|
|
m_sortMethod = items.m_sortMethod;
|
|
m_sortOrder = items.m_sortOrder;
|
|
|
|
// make a copy of each item
|
|
for (int i = 0; i < items.Size(); i++)
|
|
{
|
|
CFileItemPtr newItem(new CFileItem(*items[i]));
|
|
Add(newItem);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
CFileItemPtr CFileItemList::Get(int iItem)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
if (iItem > -1 && iItem < (int)m_items.size())
|
|
return m_items[iItem];
|
|
|
|
return CFileItemPtr();
|
|
}
|
|
|
|
const CFileItemPtr CFileItemList::Get(int iItem) const
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
if (iItem > -1 && iItem < (int)m_items.size())
|
|
return m_items[iItem];
|
|
|
|
return CFileItemPtr();
|
|
}
|
|
|
|
CFileItemPtr CFileItemList::Get(const CStdString& strPath)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
CStdString pathToCheck(strPath);
|
|
pathToCheck.ToLower();
|
|
if (m_fastLookup)
|
|
{
|
|
IMAPFILEITEMS it=m_map.find(pathToCheck);
|
|
if (it != m_map.end())
|
|
return it->second;
|
|
|
|
return CFileItemPtr();
|
|
}
|
|
// slow method...
|
|
for (unsigned int i = 0; i < m_items.size(); i++)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
if (pItem->GetPath().Equals(pathToCheck))
|
|
return pItem;
|
|
}
|
|
|
|
return CFileItemPtr();
|
|
}
|
|
|
|
const CFileItemPtr CFileItemList::Get(const CStdString& strPath) const
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
CStdString pathToCheck(strPath);
|
|
pathToCheck.ToLower();
|
|
if (m_fastLookup)
|
|
{
|
|
map<CStdString, CFileItemPtr>::const_iterator it=m_map.find(pathToCheck);
|
|
if (it != m_map.end())
|
|
return it->second;
|
|
|
|
return CFileItemPtr();
|
|
}
|
|
// slow method...
|
|
for (unsigned int i = 0; i < m_items.size(); i++)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
if (pItem->GetPath().Equals(pathToCheck))
|
|
return pItem;
|
|
}
|
|
|
|
return CFileItemPtr();
|
|
}
|
|
|
|
int CFileItemList::Size() const
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
return (int)m_items.size();
|
|
}
|
|
|
|
bool CFileItemList::IsEmpty() const
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
return (m_items.size() <= 0);
|
|
}
|
|
|
|
void CFileItemList::Reserve(int iCount)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
m_items.reserve(iCount);
|
|
}
|
|
|
|
void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
DWORD dwStart = GetTickCount();
|
|
std::stable_sort(m_items.begin(), m_items.end(), func);
|
|
DWORD dwElapsed = GetTickCount() - dwStart;
|
|
CLog::Log(LOGDEBUG,"%s, sorting took %u millis", __FUNCTION__, dwElapsed);
|
|
}
|
|
|
|
void CFileItemList::FillSortFields(FILEITEMFILLFUNC func)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
std::for_each(m_items.begin(), m_items.end(), func);
|
|
}
|
|
|
|
void CFileItemList::Sort(SORT_METHOD sortMethod, SORT_ORDER sortOrder)
|
|
{
|
|
// Already sorted?
|
|
if (sortMethod==m_sortMethod && m_sortOrder==sortOrder)
|
|
return;
|
|
|
|
switch (sortMethod)
|
|
{
|
|
case SORT_METHOD_LABEL:
|
|
case SORT_METHOD_LABEL_IGNORE_FOLDERS:
|
|
FillSortFields(SSortFileItem::ByLabel);
|
|
break;
|
|
case SORT_METHOD_LABEL_IGNORE_THE:
|
|
FillSortFields(SSortFileItem::ByLabelNoThe);
|
|
break;
|
|
case SORT_METHOD_DATE:
|
|
FillSortFields(SSortFileItem::ByDate);
|
|
break;
|
|
case SORT_METHOD_SIZE:
|
|
FillSortFields(SSortFileItem::BySize);
|
|
break;
|
|
case SORT_METHOD_BITRATE:
|
|
FillSortFields(SSortFileItem::ByBitrate);
|
|
break;
|
|
case SORT_METHOD_DRIVE_TYPE:
|
|
FillSortFields(SSortFileItem::ByDriveType);
|
|
break;
|
|
case SORT_METHOD_TRACKNUM:
|
|
FillSortFields(SSortFileItem::BySongTrackNum);
|
|
break;
|
|
case SORT_METHOD_EPISODE:
|
|
FillSortFields(SSortFileItem::ByEpisodeNum);
|
|
break;
|
|
case SORT_METHOD_DURATION:
|
|
FillSortFields(SSortFileItem::BySongDuration);
|
|
break;
|
|
case SORT_METHOD_TITLE_IGNORE_THE:
|
|
FillSortFields(SSortFileItem::BySongTitleNoThe);
|
|
break;
|
|
case SORT_METHOD_TITLE:
|
|
FillSortFields(SSortFileItem::BySongTitle);
|
|
break;
|
|
case SORT_METHOD_ARTIST:
|
|
FillSortFields(SSortFileItem::BySongArtist);
|
|
break;
|
|
case SORT_METHOD_ARTIST_IGNORE_THE:
|
|
FillSortFields(SSortFileItem::BySongArtistNoThe);
|
|
break;
|
|
case SORT_METHOD_ALBUM:
|
|
FillSortFields(SSortFileItem::BySongAlbum);
|
|
break;
|
|
case SORT_METHOD_ALBUM_IGNORE_THE:
|
|
FillSortFields(SSortFileItem::BySongAlbumNoThe);
|
|
break;
|
|
case SORT_METHOD_GENRE:
|
|
FillSortFields(SSortFileItem::ByGenre);
|
|
break;
|
|
case SORT_METHOD_DATEADDED:
|
|
FillSortFields(SSortFileItem::ByDateAdded);
|
|
break;
|
|
case SORT_METHOD_FILE:
|
|
FillSortFields(SSortFileItem::ByFile);
|
|
break;
|
|
case SORT_METHOD_VIDEO_RATING:
|
|
FillSortFields(SSortFileItem::ByMovieRating);
|
|
break;
|
|
case SORT_METHOD_VIDEO_TITLE:
|
|
FillSortFields(SSortFileItem::ByMovieTitle);
|
|
break;
|
|
case SORT_METHOD_VIDEO_SORT_TITLE:
|
|
FillSortFields(SSortFileItem::ByMovieSortTitle);
|
|
break;
|
|
case SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE:
|
|
FillSortFields(SSortFileItem::ByMovieSortTitleNoThe);
|
|
break;
|
|
case SORT_METHOD_YEAR:
|
|
FillSortFields(SSortFileItem::ByYear);
|
|
break;
|
|
case SORT_METHOD_PRODUCTIONCODE:
|
|
FillSortFields(SSortFileItem::ByProductionCode);
|
|
break;
|
|
case SORT_METHOD_PROGRAM_COUNT:
|
|
case SORT_METHOD_PLAYLIST_ORDER:
|
|
// TODO: Playlist order is hacked into program count variable (not nice, but ok until 2.0)
|
|
FillSortFields(SSortFileItem::ByProgramCount);
|
|
break;
|
|
case SORT_METHOD_SONG_RATING:
|
|
FillSortFields(SSortFileItem::BySongRating);
|
|
break;
|
|
case SORT_METHOD_MPAA_RATING:
|
|
FillSortFields(SSortFileItem::ByMPAARating);
|
|
break;
|
|
case SORT_METHOD_VIDEO_RUNTIME:
|
|
FillSortFields(SSortFileItem::ByMovieRuntime);
|
|
break;
|
|
case SORT_METHOD_STUDIO:
|
|
FillSortFields(SSortFileItem::ByStudio);
|
|
break;
|
|
case SORT_METHOD_STUDIO_IGNORE_THE:
|
|
FillSortFields(SSortFileItem::ByStudioNoThe);
|
|
break;
|
|
case SORT_METHOD_FULLPATH:
|
|
FillSortFields(SSortFileItem::ByFullPath);
|
|
break;
|
|
case SORT_METHOD_LASTPLAYED:
|
|
FillSortFields(SSortFileItem::ByLastPlayed);
|
|
break;
|
|
case SORT_METHOD_LISTENERS:
|
|
FillSortFields(SSortFileItem::ByListeners);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (sortMethod == SORT_METHOD_FILE ||
|
|
sortMethod == SORT_METHOD_VIDEO_SORT_TITLE ||
|
|
sortMethod == SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE ||
|
|
sortMethod == SORT_METHOD_LABEL_IGNORE_FOLDERS)
|
|
Sort(sortOrder==SORT_ORDER_ASC ? SSortFileItem::IgnoreFoldersAscending : SSortFileItem::IgnoreFoldersDescending);
|
|
else if (sortMethod != SORT_METHOD_NONE && sortMethod != SORT_METHOD_UNSORTED)
|
|
Sort(sortOrder==SORT_ORDER_ASC ? SSortFileItem::Ascending : SSortFileItem::Descending);
|
|
|
|
m_sortMethod=sortMethod;
|
|
m_sortOrder=sortOrder;
|
|
}
|
|
|
|
void CFileItemList::Randomize()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
random_shuffle(m_items.begin(), m_items.end());
|
|
}
|
|
|
|
void CFileItemList::Archive(CArchive& ar)
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
if (ar.IsStoring())
|
|
{
|
|
CFileItem::Archive(ar);
|
|
|
|
int i = 0;
|
|
if (m_items.size() > 0 && m_items[0]->IsParentFolder())
|
|
i = 1;
|
|
|
|
ar << (int)(m_items.size() - i);
|
|
|
|
ar << m_fastLookup;
|
|
|
|
ar << (int)m_sortMethod;
|
|
ar << (int)m_sortOrder;
|
|
ar << (int)m_cacheToDisc;
|
|
|
|
ar << (int)m_sortDetails.size();
|
|
for (unsigned int j = 0; j < m_sortDetails.size(); ++j)
|
|
{
|
|
const SORT_METHOD_DETAILS &details = m_sortDetails[j];
|
|
ar << (int)details.m_sortMethod;
|
|
ar << details.m_buttonLabel;
|
|
ar << details.m_labelMasks.m_strLabelFile;
|
|
ar << details.m_labelMasks.m_strLabelFolder;
|
|
ar << details.m_labelMasks.m_strLabel2File;
|
|
ar << details.m_labelMasks.m_strLabel2Folder;
|
|
}
|
|
|
|
ar << m_content;
|
|
|
|
for (; i < (int)m_items.size(); ++i)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
ar << *pItem;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CFileItemPtr pParent;
|
|
if (!IsEmpty())
|
|
{
|
|
CFileItemPtr pItem=m_items[0];
|
|
if (pItem->IsParentFolder())
|
|
pParent.reset(new CFileItem(*pItem));
|
|
}
|
|
|
|
SetFastLookup(false);
|
|
Clear();
|
|
|
|
|
|
CFileItem::Archive(ar);
|
|
|
|
int iSize = 0;
|
|
ar >> iSize;
|
|
if (iSize <= 0)
|
|
return ;
|
|
|
|
if (pParent)
|
|
{
|
|
m_items.reserve(iSize + 1);
|
|
m_items.push_back(pParent);
|
|
}
|
|
else
|
|
m_items.reserve(iSize);
|
|
|
|
bool fastLookup=false;
|
|
ar >> fastLookup;
|
|
|
|
int tempint;
|
|
ar >> (int&)tempint;
|
|
m_sortMethod = SORT_METHOD(tempint);
|
|
ar >> (int&)tempint;
|
|
m_sortOrder = SORT_ORDER(tempint);
|
|
ar >> (int&)tempint;
|
|
m_cacheToDisc = CACHE_TYPE(tempint);
|
|
|
|
unsigned int detailSize = 0;
|
|
ar >> detailSize;
|
|
for (unsigned int j = 0; j < detailSize; ++j)
|
|
{
|
|
SORT_METHOD_DETAILS details;
|
|
ar >> (int&)tempint;
|
|
details.m_sortMethod = SORT_METHOD(tempint);
|
|
ar >> details.m_buttonLabel;
|
|
ar >> details.m_labelMasks.m_strLabelFile;
|
|
ar >> details.m_labelMasks.m_strLabelFolder;
|
|
ar >> details.m_labelMasks.m_strLabel2File;
|
|
ar >> details.m_labelMasks.m_strLabel2Folder;
|
|
m_sortDetails.push_back(details);
|
|
}
|
|
|
|
ar >> m_content;
|
|
|
|
for (int i = 0; i < iSize; ++i)
|
|
{
|
|
CFileItemPtr pItem(new CFileItem);
|
|
ar >> *pItem;
|
|
Add(pItem);
|
|
}
|
|
|
|
SetFastLookup(fastLookup);
|
|
}
|
|
}
|
|
|
|
void CFileItemList::FillInDefaultIcons()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
for (int i = 0; i < (int)m_items.size(); ++i)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
pItem->FillInDefaultIcon();
|
|
}
|
|
}
|
|
|
|
void CFileItemList::SetMusicThumbs()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
//cache thumbnails directory
|
|
g_directoryCache.InitMusicThumbCache();
|
|
|
|
for (int i = 0; i < (int)m_items.size(); ++i)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
pItem->SetMusicThumb();
|
|
}
|
|
|
|
g_directoryCache.ClearMusicThumbCache();
|
|
}
|
|
|
|
int CFileItemList::GetFolderCount() const
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
int nFolderCount = 0;
|
|
for (int i = 0; i < (int)m_items.size(); i++)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
if (pItem->m_bIsFolder)
|
|
nFolderCount++;
|
|
}
|
|
|
|
return nFolderCount;
|
|
}
|
|
|
|
int CFileItemList::GetObjectCount() const
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
int numObjects = (int)m_items.size();
|
|
if (numObjects && m_items[0]->IsParentFolder())
|
|
numObjects--;
|
|
|
|
return numObjects;
|
|
}
|
|
|
|
int CFileItemList::GetFileCount() const
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
int nFileCount = 0;
|
|
for (int i = 0; i < (int)m_items.size(); i++)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
if (!pItem->m_bIsFolder)
|
|
nFileCount++;
|
|
}
|
|
|
|
return nFileCount;
|
|
}
|
|
|
|
int CFileItemList::GetSelectedCount() const
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
int count = 0;
|
|
for (int i = 0; i < (int)m_items.size(); i++)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
if (pItem->IsSelected())
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
void CFileItemList::FilterCueItems()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
// Handle .CUE sheet files...
|
|
VECSONGS itemstoadd;
|
|
CStdStringArray itemstodelete;
|
|
for (int i = 0; i < (int)m_items.size(); i++)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
if (!pItem->m_bIsFolder)
|
|
{ // see if it's a .CUE sheet
|
|
if (pItem->IsCUESheet())
|
|
{
|
|
CCueDocument cuesheet;
|
|
if (cuesheet.Parse(pItem->GetPath()))
|
|
{
|
|
VECSONGS newitems;
|
|
cuesheet.GetSongs(newitems);
|
|
|
|
std::vector<CStdString> MediaFileVec;
|
|
cuesheet.GetMediaFiles(MediaFileVec);
|
|
|
|
// queue the cue sheet and the underlying media file for deletion
|
|
for(std::vector<CStdString>::iterator itMedia = MediaFileVec.begin(); itMedia != MediaFileVec.end(); itMedia++)
|
|
{
|
|
CStdString strMediaFile = *itMedia;
|
|
CStdString fileFromCue = strMediaFile; // save the file from the cue we're matching against,
|
|
// as we're going to search for others here...
|
|
bool bFoundMediaFile = CFile::Exists(strMediaFile);
|
|
// queue the cue sheet and the underlying media file for deletion
|
|
if (!bFoundMediaFile)
|
|
{
|
|
// try file in same dir, not matching case...
|
|
if (Contains(strMediaFile))
|
|
{
|
|
bFoundMediaFile = true;
|
|
}
|
|
else
|
|
{
|
|
// try removing the .cue extension...
|
|
strMediaFile = pItem->GetPath();
|
|
URIUtils::RemoveExtension(strMediaFile);
|
|
CFileItem item(strMediaFile, false);
|
|
if (item.IsAudio() && Contains(strMediaFile))
|
|
{
|
|
bFoundMediaFile = true;
|
|
}
|
|
else
|
|
{ // try replacing the extension with one of our allowed ones.
|
|
CStdStringArray extensions;
|
|
StringUtils::SplitString(g_settings.m_musicExtensions, "|", extensions);
|
|
for (unsigned int i = 0; i < extensions.size(); i++)
|
|
{
|
|
strMediaFile = URIUtils::ReplaceExtension(pItem->GetPath(), extensions[i]);
|
|
CFileItem item(strMediaFile, false);
|
|
if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile))
|
|
{
|
|
bFoundMediaFile = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (bFoundMediaFile)
|
|
{
|
|
itemstodelete.push_back(pItem->GetPath());
|
|
itemstodelete.push_back(strMediaFile);
|
|
// get the additional stuff (year, genre etc.) from the underlying media files tag.
|
|
CMusicInfoTag tag;
|
|
auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(strMediaFile));
|
|
if (NULL != pLoader.get())
|
|
{
|
|
// get id3tag
|
|
pLoader->Load(strMediaFile, tag);
|
|
}
|
|
// fill in any missing entries from underlying media file
|
|
for (int j = 0; j < (int)newitems.size(); j++)
|
|
{
|
|
CSong song = newitems[j];
|
|
// only for songs that actually match the current media file
|
|
if (song.strFileName == fileFromCue)
|
|
{
|
|
// we might have a new media file from the above matching code
|
|
song.strFileName = strMediaFile;
|
|
if (tag.Loaded())
|
|
{
|
|
if (song.strAlbum.empty() && !tag.GetAlbum().empty()) song.strAlbum = tag.GetAlbum();
|
|
if (song.strAlbumArtist.empty() && !tag.GetAlbumArtist().empty()) song.strAlbumArtist = tag.GetAlbumArtist();
|
|
if (song.strGenre.empty() && !tag.GetGenre().empty()) song.strGenre = tag.GetGenre();
|
|
if (song.strArtist.empty() && !tag.GetArtist().empty()) song.strArtist = tag.GetArtist();
|
|
if (tag.GetDiscNumber()) song.iTrack |= (tag.GetDiscNumber() << 16); // see CMusicInfoTag::GetDiscNumber()
|
|
SYSTEMTIME dateTime;
|
|
tag.GetReleaseDate(dateTime);
|
|
if (dateTime.wYear) song.iYear = dateTime.wYear;
|
|
}
|
|
if (!song.iDuration && tag.GetDuration() > 0)
|
|
{ // must be the last song
|
|
song.iDuration = (tag.GetDuration() * 75 - song.iStartOffset + 37) / 75;
|
|
}
|
|
// add this item to the list
|
|
itemstoadd.push_back(song);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ // remove the .cue sheet from the directory
|
|
itemstodelete.push_back(pItem->GetPath());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ // remove the .cue sheet from the directory (can't parse it - no point listing it)
|
|
itemstodelete.push_back(pItem->GetPath());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// now delete the .CUE files and underlying media files.
|
|
for (int i = 0; i < (int)itemstodelete.size(); i++)
|
|
{
|
|
for (int j = 0; j < (int)m_items.size(); j++)
|
|
{
|
|
CFileItemPtr pItem = m_items[j];
|
|
if (stricmp(pItem->GetPath().c_str(), itemstodelete[i].c_str()) == 0)
|
|
{ // delete this item
|
|
m_items.erase(m_items.begin() + j);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// and add the files from the .CUE sheet
|
|
for (int i = 0; i < (int)itemstoadd.size(); i++)
|
|
{
|
|
// now create the file item, and add to the item list.
|
|
CFileItemPtr pItem(new CFileItem(itemstoadd[i]));
|
|
m_items.push_back(pItem);
|
|
}
|
|
}
|
|
|
|
// Remove the extensions from the filenames
|
|
void CFileItemList::RemoveExtensions()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
for (int i = 0; i < Size(); ++i)
|
|
m_items[i]->RemoveExtension();
|
|
}
|
|
|
|
void CFileItemList::Stack()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
|
|
// not allowed here
|
|
if (IsVirtualDirectoryRoot() || IsLiveTV())
|
|
return;
|
|
|
|
SetProperty("isstacked", "1");
|
|
|
|
// items needs to be sorted for stuff below to work properly
|
|
Sort(SORT_METHOD_LABEL, SORT_ORDER_ASC);
|
|
|
|
// stack folders
|
|
int i = 0;
|
|
for (i = 0; i < Size(); ++i)
|
|
{
|
|
CFileItemPtr item = Get(i);
|
|
// combined the folder checks
|
|
if (item->m_bIsFolder && !item->IsPlugin())
|
|
{
|
|
// only check known fast sources?
|
|
// xbms included because it supports file existance
|
|
// NOTES:
|
|
// 1. xbms would not have worked previously: item->GetPath().Left(5).Equals("xbms", false)
|
|
// 2. rars and zips may be on slow sources? is this supposed to be allowed?
|
|
if( !item->IsRemote()
|
|
|| item->IsSmb()
|
|
|| item->IsXBMS()
|
|
|| URIUtils::IsInRAR(item->GetPath())
|
|
|| URIUtils::IsInZIP(item->GetPath())
|
|
)
|
|
{
|
|
// stack cd# folders if contains only a single video file
|
|
// NOTE: if we're doing this anyway, why not collapse *all* folders with just a single video file?
|
|
CStdString folderName = item->GetLabel();
|
|
if (folderName.Left(2).Equals("CD") && StringUtils::IsNaturalNumber(folderName.Mid(2)))
|
|
{
|
|
CFileItemList items;
|
|
CDirectory::GetDirectory(item->GetPath(),items,g_settings.m_videoExtensions,true);
|
|
// optimized to only traverse listing once by checking for filecount
|
|
// and recording last file item for later use
|
|
int nFiles = 0;
|
|
int index = -1;
|
|
for (int j = 0; j < items.Size(); j++)
|
|
{
|
|
if (!items[j]->m_bIsFolder)
|
|
{
|
|
nFiles++;
|
|
index = j;
|
|
}
|
|
if (nFiles > 1)
|
|
break;
|
|
}
|
|
if (nFiles == 1)
|
|
{
|
|
*item = *items[index];
|
|
}
|
|
}
|
|
|
|
// check for dvd folders
|
|
else
|
|
{
|
|
CStdString path;
|
|
CStdString dvdPath;
|
|
URIUtils::AddFileToFolder(item->GetPath(), "VIDEO_TS.IFO", path);
|
|
if (CFile::Exists(path))
|
|
dvdPath = path;
|
|
else
|
|
{
|
|
URIUtils::AddFileToFolder(item->GetPath(), "VIDEO_TS", dvdPath);
|
|
URIUtils::AddFileToFolder(dvdPath, "VIDEO_TS.IFO", path);
|
|
dvdPath.Empty();
|
|
if (CFile::Exists(path))
|
|
dvdPath = path;
|
|
}
|
|
if (!dvdPath.IsEmpty())
|
|
{
|
|
// NOTE: should this be done for the CD# folders too?
|
|
/* set the thumbnail based on folder */
|
|
item->SetCachedVideoThumb();
|
|
if (!item->HasThumbnail())
|
|
item->SetUserVideoThumb();
|
|
|
|
item->m_bIsFolder = false;
|
|
item->SetPath(dvdPath);
|
|
item->SetLabel2("");
|
|
item->SetLabelPreformated(true);
|
|
m_sortMethod = SORT_METHOD_NONE; /* sorting is now broken */
|
|
|
|
/* override the previously set thumb if video_ts.ifo has any */
|
|
/* otherwise user can't set icon on the stacked file as that */
|
|
/* will allways be set on the video_ts.ifo file */
|
|
CStdString thumb(item->GetCachedVideoThumb());
|
|
if(CFile::Exists(thumb))
|
|
item->SetThumbnailImage(thumb);
|
|
else
|
|
item->SetUserVideoThumb();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Precompile our REs
|
|
VECCREGEXP stackRegExps;
|
|
CRegExp tmpRegExp(true);
|
|
const CStdStringArray& strStackRegExps = g_advancedSettings.m_videoStackRegExps;
|
|
CStdStringArray::const_iterator strRegExp = strStackRegExps.begin();
|
|
while (strRegExp != strStackRegExps.end())
|
|
{
|
|
if (tmpRegExp.RegComp(*strRegExp))
|
|
{
|
|
if (tmpRegExp.GetCaptureTotal() == 4)
|
|
stackRegExps.push_back(tmpRegExp);
|
|
else
|
|
CLog::Log(LOGERROR, "Invalid video stack RE (%s). Must have 4 captures.", strRegExp->c_str());
|
|
}
|
|
strRegExp++;
|
|
}
|
|
|
|
// now stack the files, some of which may be from the previous stack iteration
|
|
i = 0;
|
|
while (i < Size())
|
|
{
|
|
CFileItemPtr item1 = Get(i);
|
|
|
|
// set property
|
|
item1->SetProperty("isstacked", "1");
|
|
|
|
// skip folders, nfo files, playlists
|
|
if (item1->m_bIsFolder
|
|
|| item1->IsParentFolder()
|
|
|| item1->IsNFO()
|
|
|| item1->IsPlayList()
|
|
)
|
|
{
|
|
// increment index
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
int64_t size = 0;
|
|
size_t offset = 0;
|
|
CStdString stackName;
|
|
CStdString file1;
|
|
CStdString filePath;
|
|
vector<int> stack;
|
|
VECCREGEXP::iterator expr = stackRegExps.begin();
|
|
|
|
URIUtils::Split(item1->GetPath(), filePath, file1);
|
|
int j;
|
|
while (expr != stackRegExps.end())
|
|
{
|
|
if (expr->RegFind(file1, offset) != -1)
|
|
{
|
|
CStdString Title1 = expr->GetMatch(1),
|
|
Volume1 = expr->GetMatch(2),
|
|
Ignore1 = expr->GetMatch(3),
|
|
Extension1 = expr->GetMatch(4);
|
|
if (offset)
|
|
Title1 = file1.substr(0, expr->GetSubStart(2));
|
|
j = i + 1;
|
|
while (j < Size())
|
|
{
|
|
CFileItemPtr item2 = Get(j);
|
|
|
|
// skip folders, nfo files, playlists
|
|
if (item2->m_bIsFolder
|
|
|| item2->IsParentFolder()
|
|
|| item2->IsNFO()
|
|
|| item2->IsPlayList()
|
|
)
|
|
{
|
|
// increment index
|
|
j++;
|
|
continue;
|
|
}
|
|
|
|
CStdString file2, filePath2;
|
|
URIUtils::Split(item2->GetPath(), filePath2, file2);
|
|
|
|
if (expr->RegFind(file2, offset) != -1)
|
|
{
|
|
CStdString Title2 = expr->GetMatch(1),
|
|
Volume2 = expr->GetMatch(2),
|
|
Ignore2 = expr->GetMatch(3),
|
|
Extension2 = expr->GetMatch(4);
|
|
if (offset)
|
|
Title2 = file2.substr(0, expr->GetSubStart(2));
|
|
if (Title1.Equals(Title2))
|
|
{
|
|
if (!Volume1.Equals(Volume2))
|
|
{
|
|
if (Ignore1.Equals(Ignore2) && Extension1.Equals(Extension2))
|
|
{
|
|
if (stack.size() == 0)
|
|
{
|
|
stackName = Title1 + Ignore1 + Extension1;
|
|
stack.push_back(i);
|
|
size += item1->m_dwSize;
|
|
}
|
|
stack.push_back(j);
|
|
size += item2->m_dwSize;
|
|
}
|
|
else // Sequel
|
|
{
|
|
offset = 0;
|
|
expr++;
|
|
break;
|
|
}
|
|
}
|
|
else if (!Ignore1.Equals(Ignore2)) // False positive, try again with offset
|
|
{
|
|
offset = expr->GetSubStart(3);
|
|
break;
|
|
}
|
|
else // Extension mismatch
|
|
{
|
|
offset = 0;
|
|
expr++;
|
|
break;
|
|
}
|
|
}
|
|
else // Title mismatch
|
|
{
|
|
offset = 0;
|
|
expr++;
|
|
break;
|
|
}
|
|
}
|
|
else // No match 2, next expression
|
|
{
|
|
offset = 0;
|
|
expr++;
|
|
break;
|
|
}
|
|
j++;
|
|
}
|
|
if (j == Size())
|
|
expr = stackRegExps.end();
|
|
}
|
|
else // No match 1
|
|
{
|
|
offset = 0;
|
|
expr++;
|
|
}
|
|
if (stack.size() > 1)
|
|
{
|
|
// have a stack, remove the items and add the stacked item
|
|
// dont actually stack a multipart rar set, just remove all items but the first
|
|
CStdString stackPath;
|
|
if (Get(stack[0])->IsRAR())
|
|
stackPath = Get(stack[0])->GetPath();
|
|
else
|
|
{
|
|
CStackDirectory dir;
|
|
stackPath = dir.ConstructStackPath(*this, stack);
|
|
}
|
|
item1->SetPath(stackPath);
|
|
// clean up list
|
|
for (unsigned k = 1; k < stack.size(); k++)
|
|
Remove(i+1);
|
|
// item->m_bIsFolder = true; // don't treat stacked files as folders
|
|
// the label may be in a different char set from the filename (eg over smb
|
|
// the label is converted from utf8, but the filename is not)
|
|
if (!g_guiSettings.GetBool("filelists.showextensions"))
|
|
URIUtils::RemoveExtension(stackName);
|
|
CURL::Decode(stackName);
|
|
item1->SetLabel(stackName);
|
|
item1->m_dwSize = size;
|
|
break;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
bool CFileItemList::Load(int windowID)
|
|
{
|
|
CFile file;
|
|
if (file.Open(GetDiscCacheFile(windowID)))
|
|
{
|
|
CLog::Log(LOGDEBUG,"Loading fileitems [%s]",GetPath().c_str());
|
|
CArchive ar(&file, CArchive::load);
|
|
ar >> *this;
|
|
CLog::Log(LOGDEBUG," -- items: %i, directory: %s sort method: %i, ascending: %s",Size(),GetPath().c_str(), m_sortMethod, m_sortOrder ? "true" : "false");
|
|
ar.Close();
|
|
file.Close();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CFileItemList::Save(int windowID)
|
|
{
|
|
int iSize = Size();
|
|
if (iSize <= 0)
|
|
return false;
|
|
|
|
CLog::Log(LOGDEBUG,"Saving fileitems [%s]",GetPath().c_str());
|
|
|
|
CFile file;
|
|
if (file.OpenForWrite(GetDiscCacheFile(windowID), true)) // overwrite always
|
|
{
|
|
CArchive ar(&file, CArchive::store);
|
|
ar << *this;
|
|
CLog::Log(LOGDEBUG," -- items: %i, sort method: %i, ascending: %s",iSize,m_sortMethod, m_sortOrder ? "true" : "false");
|
|
ar.Close();
|
|
file.Close();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CFileItemList::RemoveDiscCache(int windowID) const
|
|
{
|
|
CStdString cacheFile(GetDiscCacheFile(windowID));
|
|
if (CFile::Exists(cacheFile))
|
|
{
|
|
CLog::Log(LOGDEBUG,"Clearing cached fileitems [%s]",GetPath().c_str());
|
|
CFile::Delete(cacheFile);
|
|
}
|
|
}
|
|
|
|
CStdString CFileItemList::GetDiscCacheFile(int windowID) const
|
|
{
|
|
CStdString strPath(GetPath());
|
|
URIUtils::RemoveSlashAtEnd(strPath);
|
|
|
|
Crc32 crc;
|
|
crc.ComputeFromLowerCase(strPath);
|
|
|
|
CStdString cacheFile;
|
|
if (IsCDDA() || IsOnDVD())
|
|
cacheFile.Format("special://temp/r-%08x.fi", (unsigned __int32)crc);
|
|
else if (IsMusicDb())
|
|
cacheFile.Format("special://temp/mdb-%08x.fi", (unsigned __int32)crc);
|
|
else if (IsVideoDb())
|
|
cacheFile.Format("special://temp/vdb-%08x.fi", (unsigned __int32)crc);
|
|
else if (windowID)
|
|
cacheFile.Format("special://temp/%i-%08x.fi", windowID, (unsigned __int32)crc);
|
|
else
|
|
cacheFile.Format("special://temp/%08x.fi", (unsigned __int32)crc);
|
|
return cacheFile;
|
|
}
|
|
|
|
bool CFileItemList::AlwaysCache() const
|
|
{
|
|
// some database folders are always cached
|
|
if (IsMusicDb())
|
|
return CMusicDatabaseDirectory::CanCache(GetPath());
|
|
if (IsVideoDb())
|
|
return CVideoDatabaseDirectory::CanCache(GetPath());
|
|
return false;
|
|
}
|
|
|
|
void CFileItemList::SetCachedVideoThumbs()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
// TODO: Investigate caching time to see if it speeds things up
|
|
for (unsigned int i = 0; i < m_items.size(); ++i)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
pItem->SetCachedVideoThumb();
|
|
}
|
|
}
|
|
|
|
void CFileItemList::SetCachedProgramThumbs()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
// TODO: Investigate caching time to see if it speeds things up
|
|
for (unsigned int i = 0; i < m_items.size(); ++i)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
pItem->SetCachedProgramThumb();
|
|
}
|
|
}
|
|
|
|
void CFileItemList::SetCachedMusicThumbs()
|
|
{
|
|
CSingleLock lock(m_lock);
|
|
// TODO: Investigate caching time to see if it speeds things up
|
|
for (unsigned int i = 0; i < m_items.size(); ++i)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
pItem->SetCachedMusicThumb();
|
|
}
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedPictureThumb() const
|
|
{
|
|
return GetCachedThumb(m_strPath,g_settings.GetPicturesThumbFolder(),true);
|
|
}
|
|
|
|
void CFileItem::SetCachedMusicThumb()
|
|
{
|
|
// if it already has a thumbnail, then return
|
|
if (HasThumbnail() || m_bIsShareOrDrive) return ;
|
|
|
|
// streams do not have thumbnails
|
|
if (IsInternetStream()) return ;
|
|
|
|
// music db items already have thumbs or there is no thumb available
|
|
if (IsMusicDb()) return;
|
|
|
|
// ignore the parent dir items
|
|
if (IsParentFolder()) return;
|
|
|
|
CStdString cachedThumb(GetPreviouslyCachedMusicThumb());
|
|
if (!cachedThumb.IsEmpty())
|
|
SetThumbnailImage(cachedThumb);
|
|
// SetIconImage(cachedThumb);
|
|
}
|
|
|
|
CStdString CFileItem::GetPreviouslyCachedMusicThumb() const
|
|
{
|
|
// look if an album thumb is available,
|
|
// could be any file with tags loaded or
|
|
// a directory in album window
|
|
CStdString strAlbum, strArtist;
|
|
if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
|
|
{
|
|
strAlbum = m_musicInfoTag->GetAlbum();
|
|
if (!m_musicInfoTag->GetAlbumArtist().IsEmpty())
|
|
strArtist = m_musicInfoTag->GetAlbumArtist();
|
|
else
|
|
strArtist = m_musicInfoTag->GetArtist();
|
|
}
|
|
if (!strAlbum.IsEmpty() && !strArtist.IsEmpty())
|
|
{
|
|
// try permanent album thumb using "album name + artist name"
|
|
CStdString thumb(CUtil::GetCachedAlbumThumb(strAlbum, strArtist));
|
|
if (CFile::Exists(thumb))
|
|
return thumb;
|
|
}
|
|
|
|
// if a file, try to find a cached filename.tbn
|
|
if (!m_bIsFolder)
|
|
{
|
|
// look for locally cached tbn
|
|
CStdString thumb(CUtil::GetCachedMusicThumb(m_strPath));
|
|
if (CFile::Exists(thumb))
|
|
return thumb;
|
|
}
|
|
|
|
// try and find a cached folder thumb (folder.jpg or folder.tbn)
|
|
CStdString strPath;
|
|
if (!m_bIsFolder)
|
|
URIUtils::GetDirectory(m_strPath, strPath);
|
|
else
|
|
strPath = m_strPath;
|
|
// music thumbs are cached without slash at end
|
|
URIUtils::RemoveSlashAtEnd(strPath);
|
|
|
|
CStdString thumb(CUtil::GetCachedMusicThumb(strPath));
|
|
if (CFile::Exists(thumb))
|
|
return thumb;
|
|
|
|
return "";
|
|
}
|
|
|
|
CStdString CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */) const
|
|
{
|
|
if (m_strPath.IsEmpty()
|
|
|| m_bIsShareOrDrive
|
|
|| IsInternetStream()
|
|
|| URIUtils::IsUPnP(m_strPath)
|
|
|| IsPlugin()
|
|
|| (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
|
|
|| IsParentFolder()
|
|
|| IsMusicDb())
|
|
return "";
|
|
|
|
// we first check for <filename>.tbn or <foldername>.tbn
|
|
CStdString fileThumb(GetTBNFile());
|
|
if (CFile::Exists(fileThumb))
|
|
return fileThumb;
|
|
|
|
// if a folder, check for folder.jpg
|
|
if (m_bIsFolder && !IsFileFolder() && (!IsRemote() || alwaysCheckRemote || g_guiSettings.GetBool("musicfiles.findremotethumbs")))
|
|
{
|
|
CStdStringArray thumbs;
|
|
StringUtils::SplitString(g_advancedSettings.m_musicThumbs, "|", thumbs);
|
|
for (unsigned int i = 0; i < thumbs.size(); ++i)
|
|
{
|
|
CStdString folderThumb(GetFolderThumb(thumbs[i]));
|
|
if (CFile::Exists(folderThumb))
|
|
{
|
|
return folderThumb;
|
|
}
|
|
}
|
|
}
|
|
// this adds support for files which inherit a folder.jpg icon which has not been cached yet.
|
|
// this occurs when queueing a top-level folder which has not been traversed yet.
|
|
else if (!IsRemote() || alwaysCheckRemote || g_guiSettings.GetBool("musicfiles.findremotethumbs"))
|
|
{
|
|
CStdString strFolder, strFile;
|
|
URIUtils::Split(m_strPath, strFolder, strFile);
|
|
if (!m_strPath.Equals(strFolder)) // any more parents to inherit from?
|
|
{
|
|
CFileItem folderItem(strFolder, true);
|
|
folderItem.SetMusicThumb(alwaysCheckRemote);
|
|
if (folderItem.HasThumbnail())
|
|
return folderItem.GetThumbnailImage();
|
|
}
|
|
}
|
|
// No thumb found
|
|
return "";
|
|
}
|
|
|
|
void CFileItem::SetUserMusicThumb(bool alwaysCheckRemote /* = false */)
|
|
{
|
|
// caches as the local thumb
|
|
CStdString thumb(GetUserMusicThumb(alwaysCheckRemote));
|
|
if (!thumb.IsEmpty())
|
|
{
|
|
CStdString cachedThumb(CUtil::GetCachedMusicThumb(m_strPath));
|
|
CPicture pic;
|
|
pic.CreateThumbnail(thumb, cachedThumb);
|
|
}
|
|
|
|
SetCachedMusicThumb();
|
|
}
|
|
|
|
void CFileItem::SetCachedPictureThumb()
|
|
{
|
|
if (IsParentFolder()) return;
|
|
CStdString cachedThumb(GetCachedPictureThumb());
|
|
if (CFile::Exists(cachedThumb))
|
|
SetThumbnailImage(cachedThumb);
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedVideoThumb() const
|
|
{
|
|
if (IsStack())
|
|
return GetCachedThumb(CStackDirectory::GetFirstStackedFile(m_strPath),g_settings.GetVideoThumbFolder(),true);
|
|
else if (IsVideoDb() && HasVideoInfoTag())
|
|
{
|
|
if (m_bIsFolder && !GetVideoInfoTag()->m_strPath.IsEmpty())
|
|
return GetCachedThumb(GetVideoInfoTag()->m_strPath, g_settings.GetVideoThumbFolder(), true);
|
|
else if (!GetVideoInfoTag()->m_strFileNameAndPath.IsEmpty())
|
|
return GetCachedThumb(GetVideoInfoTag()->m_strFileNameAndPath, g_settings.GetVideoThumbFolder(), true);
|
|
}
|
|
return GetCachedThumb(m_strPath,g_settings.GetVideoThumbFolder(),true);
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedEpisodeThumb() const
|
|
{
|
|
// get the locally cached thumb
|
|
CStdString strCRC;
|
|
strCRC.Format("%sepisode%i",GetVideoInfoTag()->m_strFileNameAndPath.c_str(),GetVideoInfoTag()->m_iEpisode);
|
|
return GetCachedThumb(strCRC,g_settings.GetVideoThumbFolder(),true);
|
|
}
|
|
|
|
void CFileItem::SetCachedVideoThumb()
|
|
{
|
|
if (IsParentFolder()) return;
|
|
if (HasThumbnail()) return;
|
|
CStdString cachedThumb(GetCachedVideoThumb());
|
|
if (HasVideoInfoTag() && !m_bIsFolder &&
|
|
GetVideoInfoTag()->m_iEpisode > -1 &&
|
|
CFile::Exists(GetCachedEpisodeThumb()))
|
|
{
|
|
SetThumbnailImage(GetCachedEpisodeThumb());
|
|
}
|
|
else if (CFile::Exists(cachedThumb))
|
|
SetThumbnailImage(cachedThumb);
|
|
}
|
|
|
|
// Gets the .tbn filename from a file or folder name.
|
|
// <filename>.ext -> <filename>.tbn
|
|
// <foldername>/ -> <foldername>.tbn
|
|
CStdString CFileItem::GetTBNFile() const
|
|
{
|
|
CStdString thumbFile;
|
|
CStdString strFile = m_strPath;
|
|
|
|
if (IsStack())
|
|
{
|
|
CStdString strPath, strReturn;
|
|
URIUtils::GetParentPath(m_strPath,strPath);
|
|
CFileItem item(CStackDirectory::GetFirstStackedFile(strFile),false);
|
|
CStdString strTBNFile = item.GetTBNFile();
|
|
URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strReturn);
|
|
if (CFile::Exists(strReturn))
|
|
return strReturn;
|
|
|
|
URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(strFile)),strFile);
|
|
}
|
|
|
|
if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
|
|
{
|
|
CStdString strPath, strParent;
|
|
URIUtils::GetDirectory(strFile,strPath);
|
|
URIUtils::GetParentPath(strPath,strParent);
|
|
URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
|
|
}
|
|
|
|
CURL url(strFile);
|
|
strFile = url.GetFileName();
|
|
|
|
if (m_bIsFolder && !IsFileFolder())
|
|
URIUtils::RemoveSlashAtEnd(strFile);
|
|
|
|
if (!strFile.IsEmpty())
|
|
{
|
|
if (m_bIsFolder && !IsFileFolder())
|
|
thumbFile = strFile + ".tbn"; // folder, so just add ".tbn"
|
|
else
|
|
thumbFile = URIUtils::ReplaceExtension(strFile, ".tbn");
|
|
url.SetFileName(thumbFile);
|
|
thumbFile = url.Get();
|
|
}
|
|
return thumbFile;
|
|
}
|
|
|
|
CStdString CFileItem::GetUserVideoThumb() const
|
|
{
|
|
if (IsTuxBox())
|
|
{
|
|
if (!m_bIsFolder)
|
|
return g_tuxbox.GetPicon(GetLabel());
|
|
else return "";
|
|
}
|
|
|
|
if (m_strPath.IsEmpty()
|
|
|| m_bIsShareOrDrive
|
|
|| IsInternetStream()
|
|
|| URIUtils::IsUPnP(m_strPath)
|
|
|| m_strPath.Left(4).Equals("dvd:")
|
|
|| (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
|
|
|| IsPlugin()
|
|
|| IsParentFolder()
|
|
|| IsLiveTV())
|
|
return "";
|
|
|
|
|
|
// 1. check <filename>.tbn or <foldername>.tbn
|
|
CStdString fileThumb(GetTBNFile());
|
|
if (CFile::Exists(fileThumb))
|
|
return fileThumb;
|
|
|
|
// 2. - check movie.tbn, as long as it's not a folder
|
|
if (!m_bIsFolder)
|
|
{
|
|
CStdString strPath, movietbnFile;
|
|
URIUtils::GetParentPath(m_strPath, strPath);
|
|
URIUtils::AddFileToFolder(strPath, "movie.tbn", movietbnFile);
|
|
if (CFile::Exists(movietbnFile))
|
|
return movietbnFile;
|
|
}
|
|
|
|
// 3. check folder image in_m_dvdThumbs (folder.jpg)
|
|
if (m_bIsFolder && !IsFileFolder())
|
|
{
|
|
CStdStringArray thumbs;
|
|
StringUtils::SplitString(g_advancedSettings.m_dvdThumbs, "|", thumbs);
|
|
for (unsigned int i = 0; i < thumbs.size(); ++i)
|
|
{
|
|
CStdString folderThumb(GetFolderThumb(thumbs[i]));
|
|
if (CFile::Exists(folderThumb))
|
|
{
|
|
return folderThumb;
|
|
}
|
|
}
|
|
}
|
|
// No thumb found
|
|
return "";
|
|
}
|
|
|
|
CStdString CFileItem::GetFolderThumb(const CStdString &folderJPG /* = "folder.jpg" */) const
|
|
{
|
|
CStdString folderThumb;
|
|
CStdString strFolder = m_strPath;
|
|
|
|
if (IsStack() ||
|
|
URIUtils::IsInRAR(strFolder) ||
|
|
URIUtils::IsInZIP(strFolder))
|
|
{
|
|
URIUtils::GetParentPath(m_strPath,strFolder);
|
|
}
|
|
|
|
if (IsMultiPath())
|
|
strFolder = CMultiPathDirectory::GetFirstPath(m_strPath);
|
|
|
|
URIUtils::AddFileToFolder(strFolder, folderJPG, folderThumb);
|
|
return folderThumb;
|
|
}
|
|
|
|
CStdString CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const
|
|
{
|
|
if (IsLabelPreformated())
|
|
return GetLabel();
|
|
|
|
CStdString strMovieName = m_strPath;
|
|
|
|
if (IsMultiPath())
|
|
strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
|
|
|
|
if (URIUtils::IsStack(strMovieName))
|
|
strMovieName = CStackDirectory::GetStackedTitlePath(strMovieName);
|
|
|
|
if ((!m_bIsFolder || IsDVDFile(false, true) || URIUtils::IsInArchive(m_strPath)) && bUseFolderNames)
|
|
{
|
|
URIUtils::GetParentPath(m_strPath, strMovieName);
|
|
if (URIUtils::IsInArchive(m_strPath) || strMovieName.Find( "VIDEO_TS" ) != -1)
|
|
{
|
|
CStdString strArchivePath;
|
|
URIUtils::GetParentPath(strMovieName, strArchivePath);
|
|
strMovieName = strArchivePath;
|
|
}
|
|
}
|
|
|
|
URIUtils::RemoveSlashAtEnd(strMovieName);
|
|
strMovieName = URIUtils::GetFileName(strMovieName);
|
|
CURL::Decode(strMovieName);
|
|
|
|
return strMovieName;
|
|
}
|
|
|
|
void CFileItem::SetVideoThumb()
|
|
{
|
|
if (HasThumbnail()) return;
|
|
SetCachedVideoThumb();
|
|
if (!HasThumbnail())
|
|
SetUserVideoThumb();
|
|
}
|
|
|
|
void CFileItem::SetUserVideoThumb()
|
|
{
|
|
if (m_bIsShareOrDrive) return;
|
|
if (IsParentFolder()) return;
|
|
|
|
// caches as the local thumb
|
|
CStdString thumb(GetUserVideoThumb());
|
|
if (!thumb.IsEmpty())
|
|
{
|
|
CStdString cachedThumb(GetCachedVideoThumb());
|
|
CPicture pic;
|
|
pic.CreateThumbnail(thumb, cachedThumb);
|
|
}
|
|
SetCachedVideoThumb();
|
|
}
|
|
|
|
bool CFileItem::CacheLocalFanart() const
|
|
{
|
|
// first check for an already cached fanart image
|
|
CStdString cachedFanart(GetCachedFanart());
|
|
if (CFile::Exists(cachedFanart))
|
|
return true;
|
|
|
|
// we don't have a cached image, so let's see if the user has a local image, and cache it if so
|
|
CStdString localFanart(GetLocalFanart());
|
|
if (!localFanart.IsEmpty())
|
|
{
|
|
CPicture pic;
|
|
return pic.CacheFanart(localFanart, cachedFanart);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
CStdString CFileItem::GetLocalFanart() const
|
|
{
|
|
if (IsVideoDb())
|
|
{
|
|
if (!HasVideoInfoTag())
|
|
return ""; // nothing can be done
|
|
CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
|
|
return dbItem.GetLocalFanart();
|
|
}
|
|
|
|
CStdString strFile2;
|
|
CStdString strFile = m_strPath;
|
|
if (IsStack())
|
|
{
|
|
CStdString strPath;
|
|
URIUtils::GetParentPath(m_strPath,strPath);
|
|
CStackDirectory dir;
|
|
CStdString strPath2;
|
|
strPath2 = dir.GetStackedTitlePath(strFile);
|
|
URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2),strFile);
|
|
CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
|
|
CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-fanart"));
|
|
URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strFile2);
|
|
}
|
|
if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
|
|
{
|
|
CStdString strPath, strParent;
|
|
URIUtils::GetDirectory(strFile,strPath);
|
|
URIUtils::GetParentPath(strPath,strParent);
|
|
URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
|
|
}
|
|
|
|
// no local fanart available for these
|
|
if (IsInternetStream()
|
|
|| URIUtils::IsUPnP(strFile)
|
|
|| IsLiveTV()
|
|
|| IsPlugin()
|
|
|| m_strPath.Left(4).Equals("dvd:")
|
|
|| (URIUtils::IsFTP(strFile) && !g_advancedSettings.m_bFTPThumbs)
|
|
|| m_strPath.IsEmpty())
|
|
return "";
|
|
|
|
CStdString strDir;
|
|
URIUtils::GetDirectory(strFile, strDir);
|
|
|
|
if (strDir.IsEmpty())
|
|
return "";
|
|
|
|
CFileItemList items;
|
|
CDirectory::GetDirectory(strDir, items, g_settings.m_pictureExtensions, false, false, DIR_CACHE_ALWAYS, false);
|
|
|
|
CStdStringArray fanarts;
|
|
StringUtils::SplitString(g_advancedSettings.m_fanartImages, "|", fanarts);
|
|
|
|
strFile = URIUtils::ReplaceExtension(strFile, "-fanart");
|
|
fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile));
|
|
|
|
if (!strFile2.IsEmpty())
|
|
fanarts.insert(m_bIsFolder ? fanarts.end() : fanarts.begin(), URIUtils::GetFileName(strFile2));
|
|
|
|
for (unsigned int i = 0; i < fanarts.size(); ++i)
|
|
{
|
|
for (int j = 0; j < items.Size(); j++)
|
|
{
|
|
CStdString strCandidate = URIUtils::GetFileName(items[j]->m_strPath);
|
|
URIUtils::RemoveExtension(strCandidate);
|
|
CStdString strFanart = fanarts[i];
|
|
URIUtils::RemoveExtension(strFanart);
|
|
if (strCandidate.CompareNoCase(strFanart) == 0)
|
|
return items[j]->m_strPath;
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedFanart() const
|
|
{
|
|
// get the locally cached thumb
|
|
if (IsVideoDb())
|
|
{
|
|
if (!HasVideoInfoTag())
|
|
return "";
|
|
if (!GetVideoInfoTag()->m_strArtist.IsEmpty())
|
|
return GetCachedThumb(GetVideoInfoTag()->m_strArtist,g_settings.GetMusicFanartFolder());
|
|
if (!m_bIsFolder && !GetVideoInfoTag()->m_strShowTitle.IsEmpty())
|
|
{
|
|
CVideoDatabase database;
|
|
database.Open();
|
|
int iShowId = database.GetTvShowId(GetVideoInfoTag()->m_strPath);
|
|
CStdString showPath;
|
|
database.GetFilePathById(iShowId,showPath,VIDEODB_CONTENT_TVSHOWS);
|
|
return GetCachedThumb(showPath,g_settings.GetVideoFanartFolder());
|
|
}
|
|
return GetCachedThumb(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath,g_settings.GetVideoFanartFolder());
|
|
}
|
|
if (HasMusicInfoTag())
|
|
return GetCachedThumb(GetMusicInfoTag()->GetArtist(),g_settings.GetMusicFanartFolder());
|
|
|
|
return GetCachedThumb(m_strPath,g_settings.GetVideoFanartFolder());
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedThumb(const CStdString &path, const CStdString &path2, bool split)
|
|
{
|
|
// get the locally cached thumb
|
|
Crc32 crc;
|
|
crc.ComputeFromLowerCase(path);
|
|
|
|
CStdString thumb;
|
|
if (split)
|
|
{
|
|
CStdString hex;
|
|
hex.Format("%08x", (__int32)crc);
|
|
thumb.Format("%c\\%08x.tbn", hex[0], (unsigned __int32)crc);
|
|
}
|
|
else
|
|
thumb.Format("%08x.tbn", (unsigned __int32)crc);
|
|
|
|
return URIUtils::AddFileToFolder(path2, thumb);
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedProgramThumb() const
|
|
{
|
|
// get the locally cached thumb
|
|
Crc32 crc;
|
|
if (IsOnDVD())
|
|
{
|
|
CStdString strDesc;
|
|
CUtil::GetXBEDescription(m_strPath,strDesc);
|
|
CStdString strCRC;
|
|
strCRC.Format("%s%u",strDesc.c_str(),CUtil::GetXbeID(m_strPath));
|
|
crc.ComputeFromLowerCase(strCRC);
|
|
}
|
|
else
|
|
crc.ComputeFromLowerCase(m_strPath);
|
|
|
|
CStdString hex;
|
|
hex.Format("%08x", (__int32)crc);
|
|
|
|
CStdString thumb;
|
|
|
|
thumb.Format("%s\\%c\\%08x.tbn", g_settings.GetProgramsThumbFolder().c_str(), hex[0], (unsigned __int32)crc);
|
|
|
|
return thumb;
|
|
}
|
|
|
|
CStdString CFileItem::GetCachedGameSaveThumb() const
|
|
{
|
|
CStdString extension;
|
|
URIUtils::GetExtension(m_strPath,extension);
|
|
if (extension.Equals(".xbx")) // savemeta.xbx - cache thumb
|
|
{
|
|
CStdString thumb = GetCachedThumb(m_strPath,g_settings.GetGameSaveThumbFolder());
|
|
CLog::Log(LOGDEBUG, "Thumb (%s)",thumb.c_str());
|
|
if (!CFile::Exists(thumb))
|
|
{
|
|
CStdString strTitleImage, strParent, strParentSave, strParentTitle;
|
|
URIUtils::GetDirectory(m_strPath,strTitleImage);
|
|
URIUtils::GetParentPath(strTitleImage,strParent);
|
|
URIUtils::AddFileToFolder(strTitleImage,"saveimage.xbx",strTitleImage);
|
|
URIUtils::AddFileToFolder(strParent,"saveimage.xbx",strParentSave);
|
|
URIUtils::AddFileToFolder(strParent,"titleimage.xbx",strParentTitle);
|
|
//URIUtils::AddFileToFolder(strTitleImageCur,"titleimage.xbx",m_strPath);
|
|
if (CFile::Exists(strTitleImage))
|
|
CUtil::CacheXBEIcon(strTitleImage, thumb);
|
|
else if (CFile::Exists(strParentSave))
|
|
CUtil::CacheXBEIcon(strParentSave,thumb);
|
|
else if (CFile::Exists(strParentTitle))
|
|
CUtil::CacheXBEIcon(strParentTitle,thumb);
|
|
else
|
|
thumb = "";
|
|
}
|
|
return thumb;
|
|
}
|
|
else if (CDirectory::Exists(m_strPath))
|
|
{
|
|
// get the save game id
|
|
CStdString fullPath(m_strPath);
|
|
URIUtils::RemoveSlashAtEnd(fullPath);
|
|
CStdString fileName(URIUtils::GetFileName(fullPath));
|
|
|
|
CStdString thumb;
|
|
thumb.Format("%s\\%s.tbn", g_settings.GetGameSaveThumbFolder().c_str(), fileName.c_str());
|
|
CLog::Log(LOGDEBUG, "Thumb (%s)",thumb.c_str());
|
|
if (!CFile::Exists(thumb))
|
|
{
|
|
CStdString titleimageXBX;
|
|
CStdString saveimageXBX;
|
|
|
|
URIUtils::AddFileToFolder(m_strPath, "titleimage.xbx", titleimageXBX);
|
|
URIUtils::AddFileToFolder(m_strPath,"saveimage.xbx",saveimageXBX);
|
|
|
|
/*if (CFile::Exists(saveimageXBX))
|
|
{
|
|
CUtil::CacheXBEIcon(saveimageXBX, thumb);
|
|
CLog::Log(LOGDEBUG, "saveimageXBX (%s)",saveimageXBX.c_str());
|
|
}*/
|
|
if (CFile::Exists(titleimageXBX))
|
|
{
|
|
CLog::Log(LOGDEBUG, "titleimageXBX (%s)",titleimageXBX.c_str());
|
|
CUtil::CacheXBEIcon(titleimageXBX, thumb);
|
|
}
|
|
}
|
|
return thumb;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
void CFileItem::SetCachedProgramThumb()
|
|
{
|
|
// don't set any thumb for programs on DVD, as they're bound to be named the
|
|
// same (D:\default.xbe).
|
|
if (IsParentFolder()) return;
|
|
CStdString thumb(GetCachedProgramThumb());
|
|
if (CFile::Exists(thumb))
|
|
SetThumbnailImage(thumb);
|
|
}
|
|
|
|
void CFileItem::SetUserProgramThumb()
|
|
{
|
|
if (m_bIsShareOrDrive) return;
|
|
if (IsParentFolder()) return;
|
|
|
|
if (IsShortCut())
|
|
{
|
|
CShortcut shortcut;
|
|
if ( shortcut.Create(m_strPath) && !shortcut.m_strThumb.IsEmpty() )
|
|
{
|
|
m_strThumbnailImage = shortcut.m_strThumb;
|
|
return;
|
|
}
|
|
}
|
|
// 1. Try <filename>.tbn
|
|
CStdString fileThumb(GetTBNFile());
|
|
CStdString thumb(GetCachedProgramThumb());
|
|
if (CFile::Exists(fileThumb))
|
|
{ // cache
|
|
CPicture pic;
|
|
if (pic.CreateThumbnail(fileThumb, thumb))
|
|
SetThumbnailImage(thumb);
|
|
}
|
|
else if (IsXBE())
|
|
{
|
|
// 2. check for avalaunch_icon.jpg
|
|
CStdString directory;
|
|
URIUtils::GetDirectory(m_strPath, directory);
|
|
CStdString avalaunchIcon;
|
|
URIUtils::AddFileToFolder(directory, "avalaunch_icon.jpg", avalaunchIcon);
|
|
if (CFile::Exists(avalaunchIcon))
|
|
{
|
|
CPicture pic;
|
|
if (pic.CreateThumbnail(avalaunchIcon, thumb))
|
|
SetThumbnailImage(thumb);
|
|
}
|
|
else if (CUtil::CacheXBEIcon(m_strPath, thumb))
|
|
SetThumbnailImage(thumb);
|
|
}
|
|
else if (m_bIsFolder)
|
|
{
|
|
// 3. cache the folder image
|
|
CStdString folderThumb(GetFolderThumb());
|
|
if (CFile::Exists(folderThumb))
|
|
{
|
|
CPicture pic;
|
|
if (pic.CreateThumbnail(folderThumb, thumb))
|
|
SetThumbnailImage(thumb);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*void CFileItem::SetThumb()
|
|
{
|
|
// we need to know the type of file at this point
|
|
// as differing views have differing inheritance rules for thumbs:
|
|
|
|
// Videos:
|
|
// Folders only use <foldername>/folder.jpg or <foldername>.tbn
|
|
// Files use <filename>.tbn
|
|
// * Thumbs are cached from here using file or folder path
|
|
|
|
// Music:
|
|
// Folders only use <foldername>/folder.jpg or <foldername>.tbn
|
|
// Files use <filename>.tbn or the album/path cached thumb or inherit from the folder
|
|
// * Thumbs are cached from here using file or folder path
|
|
|
|
// Programs:
|
|
// Folders only use <foldername>/folder.jpg or <foldername>.tbn
|
|
// Files use <filename>.tbn or the embedded xbe. Shortcuts have the additional step of the <thumbnail> tag to check
|
|
// * Thumbs are cached from here using file or folder path
|
|
|
|
// Pictures:
|
|
// Folders use <foldername>/folder.jpg or <foldername>.tbn, or auto-generated from 4 images in the folder
|
|
// Files use <filename>.tbn or a resized version of the picture
|
|
// * Thumbs are cached from here using file or folder path
|
|
|
|
}*/
|
|
|
|
void CFileItemList::SetProgramThumbs()
|
|
{
|
|
// TODO: Is there a speed up if we cache the program thumbs first?
|
|
for (unsigned int i = 0; i < m_items.size(); i++)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
if (pItem->IsParentFolder())
|
|
continue;
|
|
pItem->SetCachedProgramThumb();
|
|
if (!pItem->HasThumbnail())
|
|
pItem->SetUserProgramThumb();
|
|
}
|
|
}
|
|
|
|
bool CFileItem::LoadMusicTag()
|
|
{
|
|
// not audio
|
|
if (!IsAudio())
|
|
return false;
|
|
// already loaded?
|
|
if (HasMusicInfoTag() && m_musicInfoTag->Loaded())
|
|
return true;
|
|
// check db
|
|
CMusicDatabase musicDatabase;
|
|
if (musicDatabase.Open())
|
|
{
|
|
CSong song;
|
|
if (musicDatabase.GetSongByFileName(m_strPath, song))
|
|
{
|
|
GetMusicInfoTag()->SetSong(song);
|
|
SetThumbnailImage(song.strThumb);
|
|
return true;
|
|
}
|
|
musicDatabase.Close();
|
|
}
|
|
// load tag from file
|
|
CLog::Log(LOGDEBUG, "%s: loading tag information for file: %s", __FUNCTION__, m_strPath.c_str());
|
|
CMusicInfoTagLoaderFactory factory;
|
|
auto_ptr<IMusicInfoTagLoader> pLoader (factory.CreateLoader(m_strPath));
|
|
if (NULL != pLoader.get())
|
|
{
|
|
if (pLoader->Load(m_strPath, *GetMusicInfoTag()))
|
|
return true;
|
|
}
|
|
// no tag - try some other things
|
|
if (IsCDDA())
|
|
{
|
|
// we have the tracknumber...
|
|
int iTrack = GetMusicInfoTag()->GetTrackNumber();
|
|
if (iTrack >= 1)
|
|
{
|
|
CStdString strText = g_localizeStrings.Get(554); // "Track"
|
|
if (strText.GetAt(strText.size() - 1) != ' ')
|
|
strText += " ";
|
|
CStdString strTrack;
|
|
strTrack.Format(strText + "%i", iTrack);
|
|
GetMusicInfoTag()->SetTitle(strTrack);
|
|
GetMusicInfoTag()->SetLoaded(true);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CStdString fileName = URIUtils::GetFileName(m_strPath);
|
|
URIUtils::RemoveExtension(fileName);
|
|
for (unsigned int i = 0; i < g_advancedSettings.m_musicTagsFromFileFilters.size(); i++)
|
|
{
|
|
CLabelFormatter formatter(g_advancedSettings.m_musicTagsFromFileFilters[i], "");
|
|
if (formatter.FillMusicTag(fileName, GetMusicInfoTag()))
|
|
{
|
|
GetMusicInfoTag()->SetLoaded(true);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CFileItem::SetCachedGameSavesThumb()
|
|
{
|
|
if (IsParentFolder()) return;
|
|
CStdString thumb(GetCachedGameSaveThumb());
|
|
if (CFile::Exists(thumb))
|
|
SetThumbnailImage(thumb);
|
|
}
|
|
|
|
void CFileItemList::SetCachedGameSavesThumbs()
|
|
{
|
|
// TODO: Investigate caching time to see if it speeds things up
|
|
for (unsigned int i = 0; i < m_items.size(); ++i)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
pItem->SetCachedGameSavesThumb();
|
|
}
|
|
}
|
|
|
|
void CFileItemList::SetGameSavesThumbs()
|
|
{
|
|
// No User thumbs
|
|
// TODO: Is there a speed up if we cache the program thumbs first?
|
|
for (unsigned int i = 0; i < m_items.size(); i++)
|
|
{
|
|
CFileItemPtr pItem = m_items[i];
|
|
if (pItem->IsParentFolder())
|
|
continue;
|
|
pItem->SetCachedGameSavesThumb(); // was pItem->SetCachedProgramThumb(); oringally
|
|
}
|
|
}
|
|
|
|
void CFileItemList::Swap(unsigned int item1, unsigned int item2)
|
|
{
|
|
if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size())
|
|
std::swap(m_items[item1], m_items[item2]);
|
|
}
|
|
|
|
bool CFileItemList::UpdateItem(const CFileItem *item)
|
|
{
|
|
if (!item) return false;
|
|
CFileItemPtr oldItem = Get(item->GetPath());
|
|
if (oldItem)
|
|
*oldItem = *item;
|
|
return oldItem;
|
|
}
|
|
|
|
void CFileItemList::AddSortMethod(SORT_METHOD sortMethod, int buttonLabel, const LABEL_MASKS &labelMasks)
|
|
{
|
|
SORT_METHOD_DETAILS sort;
|
|
sort.m_sortMethod=sortMethod;
|
|
sort.m_buttonLabel=buttonLabel;
|
|
sort.m_labelMasks=labelMasks;
|
|
|
|
m_sortDetails.push_back(sort);
|
|
}
|
|
|
|
void CFileItemList::SetReplaceListing(bool replace)
|
|
{
|
|
m_replaceListing = replace;
|
|
}
|
|
|
|
void CFileItemList::ClearSortState()
|
|
{
|
|
m_sortMethod=SORT_METHOD_NONE;
|
|
m_sortOrder=SORT_ORDER_NONE;
|
|
}
|
|
|
|
CVideoInfoTag* CFileItem::GetVideoInfoTag()
|
|
{
|
|
if (!m_videoInfoTag)
|
|
m_videoInfoTag = new CVideoInfoTag;
|
|
|
|
return m_videoInfoTag;
|
|
}
|
|
|
|
CPictureInfoTag* CFileItem::GetPictureInfoTag()
|
|
{
|
|
if (!m_pictureInfoTag)
|
|
m_pictureInfoTag = new CPictureInfoTag;
|
|
|
|
return m_pictureInfoTag;
|
|
}
|
|
|
|
MUSIC_INFO::CMusicInfoTag* CFileItem::GetMusicInfoTag()
|
|
{
|
|
if (!m_musicInfoTag)
|
|
m_musicInfoTag = new MUSIC_INFO::CMusicInfoTag;
|
|
|
|
return m_musicInfoTag;
|
|
}
|
|
|
|
CStdString CFileItem::FindTrailer() const
|
|
{
|
|
CStdString strFile2;
|
|
CStdString strFile = m_strPath;
|
|
if (IsStack())
|
|
{
|
|
CStdString strPath;
|
|
URIUtils::GetParentPath(m_strPath,strPath);
|
|
CStackDirectory dir;
|
|
CStdString strPath2;
|
|
strPath2 = dir.GetStackedTitlePath(strFile);
|
|
URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strPath2),strFile);
|
|
CFileItem item(dir.GetFirstStackedFile(m_strPath),false);
|
|
CStdString strTBNFile(URIUtils::ReplaceExtension(item.GetTBNFile(), "-trailer"));
|
|
URIUtils::AddFileToFolder(strPath,URIUtils::GetFileName(strTBNFile),strFile2);
|
|
}
|
|
if (URIUtils::IsInRAR(strFile) || URIUtils::IsInZIP(strFile))
|
|
{
|
|
CStdString strPath, strParent;
|
|
URIUtils::GetDirectory(strFile,strPath);
|
|
URIUtils::GetParentPath(strPath,strParent);
|
|
URIUtils::AddFileToFolder(strParent,URIUtils::GetFileName(m_strPath),strFile);
|
|
}
|
|
|
|
// no local trailer available for these
|
|
if (IsInternetStream()
|
|
|| URIUtils::IsUPnP(strFile)
|
|
|| IsLiveTV()
|
|
|| IsPlugin()
|
|
|| m_strPath.Left(4).Equals("dvd:"))
|
|
return "";
|
|
|
|
CStdString strDir;
|
|
URIUtils::GetDirectory(strFile, strDir);
|
|
CFileItemList items;
|
|
CDirectory::GetDirectory(strDir, items, g_settings.m_videoExtensions, true, false, DIR_CACHE_ALWAYS, false);
|
|
URIUtils::RemoveExtension(strFile);
|
|
strFile += "-trailer";
|
|
CStdString strFile3 = URIUtils::AddFileToFolder(strDir, "movie-trailer");
|
|
|
|
// Precompile our REs
|
|
VECCREGEXP matchRegExps;
|
|
CRegExp tmpRegExp(true);
|
|
const CStdStringArray& strMatchRegExps = g_advancedSettings.m_trailerMatchRegExps;
|
|
|
|
CStdStringArray::const_iterator strRegExp = strMatchRegExps.begin();
|
|
while (strRegExp != strMatchRegExps.end())
|
|
{
|
|
if (tmpRegExp.RegComp(*strRegExp))
|
|
{
|
|
matchRegExps.push_back(tmpRegExp);
|
|
}
|
|
strRegExp++;
|
|
}
|
|
|
|
CStdString strTrailer;
|
|
for (int i = 0; i < items.Size(); i++)
|
|
{
|
|
CStdString strCandidate = items[i]->m_strPath;
|
|
URIUtils::RemoveExtension(strCandidate);
|
|
if (strCandidate.CompareNoCase(strFile) == 0 ||
|
|
strCandidate.CompareNoCase(strFile2) == 0 ||
|
|
strCandidate.CompareNoCase(strFile3) == 0)
|
|
{
|
|
strTrailer = items[i]->m_strPath;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
VECCREGEXP::iterator expr = matchRegExps.begin();
|
|
|
|
while (expr != matchRegExps.end())
|
|
{
|
|
if (expr->RegFind(strCandidate) != -1)
|
|
{
|
|
strTrailer = items[i]->m_strPath;
|
|
i = items.Size();
|
|
break;
|
|
}
|
|
expr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return strTrailer;
|
|
}
|
|
|
|
VIDEODB_CONTENT_TYPE CFileItem::GetVideoContentType() const
|
|
{
|
|
VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
|
|
if (HasVideoInfoTag() && !GetVideoInfoTag()->m_strShowTitle.IsEmpty()) // tvshow
|
|
type = VIDEODB_CONTENT_TVSHOWS;
|
|
if (HasVideoInfoTag() && GetVideoInfoTag()->m_iSeason > -1 && !m_bIsFolder) // episode
|
|
type = VIDEODB_CONTENT_EPISODES;
|
|
if (HasVideoInfoTag() && !GetVideoInfoTag()->m_strArtist.IsEmpty())
|
|
type = VIDEODB_CONTENT_MUSICVIDEOS;
|
|
return type;
|
|
}
|
|
|