Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

2956 lines (2607 sloc) 79.059 kB
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.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, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "FileItem.h"
#include "guilib/LocalizeStrings.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
#include "Util.h"
#include "playlists/PlayListFactory.h"
#include "utils/Crc32.h"
#include "filesystem/Directory.h"
#include "filesystem/StackDirectory.h"
#include "filesystem/CurlFile.h"
#include "filesystem/MultiPathDirectory.h"
#include "filesystem/MusicDatabaseDirectory.h"
#include "filesystem/VideoDatabaseDirectory.h"
#include "music/tags/MusicInfoTagLoaderFactory.h"
#include "CueDocument.h"
#include "video/VideoDatabase.h"
#include "music/MusicDatabase.h"
#include "utils/TuxBoxUtil.h"
#include "video/VideoInfoTag.h"
#include "threads/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/GUISettings.h"
#include "settings/AdvancedSettings.h"
#include "settings/Settings.h"
#include "utils/RegExp.h"
#include "utils/log.h"
#include "utils/Variant.h"
#include "music/karaoke/karaokelyricsfactory.h"
#include "utils/Mime.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_lStartPartNumber = 0;
SetProperty("item_start", 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 = StringUtils::Join(album.artist, g_advancedSettings.m_musicItemSeparator);
URIUtils::AddSlashAtEnd(m_strPath);
GetMusicInfoTag()->SetAlbum(album);
m_bIsAlbum = true;
CMusicDatabase::SetPropertiesFromAlbum(*this,album);
}
CFileItem::CFileItem(const CMusicInfoTag& music)
{
m_musicInfoTag = NULL;
m_videoInfoTag = NULL;
m_pictureInfoTag = NULL;
Reset();
SetLabel(music.GetTitle());
m_strPath = music.GetURL();
m_bIsFolder = URIUtils::HasSlashAtEnd(m_strPath);
*GetMusicInfoTag() = music;
FillInDefaultIcon();
}
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;
if (movie.m_iSeason == 0) SetProperty("isspecial", "true");
FillInDefaultIcon();
}
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))
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);
if (IsDVD())
GetVideoInfoTag()->m_strFileNameAndPath = share.strDiskUniqueId; // share.strDiskUniqueId contains disc unique id
}
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_lStartPartNumber = item.m_lStartPartNumber;
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;
m_bIsAlbum = item.m_bIsAlbum;
return *this;
}
void CFileItem::Reset()
{
m_strLabel2.Empty();
SetLabel("");
m_bLabelPreformated=false;
FreeIcons();
m_overlayIcon = ICON_OVERLAY_NONE;
m_bSelected = false;
m_bIsAlbum = 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_lStartPartNumber = 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 = SortSpecialNone;
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_lStartPartNumber;
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_lStartPartNumber;
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 = (SortSpecial)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"] = GetMimeType();
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"]);
}
void CFileItem::ToSortable(SortItem &sortable)
{
sortable[FieldPath] = m_strPath;
sortable[FieldDate] = (m_dateTime.IsValid()) ? m_dateTime.GetAsDBDateTime() : "";
sortable[FieldSize] = m_dwSize;
sortable[FieldDriveType] = m_iDriveType;
sortable[FieldStartOffset] = m_lStartOffset;
sortable[FieldStartOffset] = m_lEndOffset;
sortable[FieldProgramCount] = m_iprogramCount;
sortable[FieldBitrate] = m_dwSize;
sortable[FieldTitle] = m_strTitle;
sortable[FieldSortSpecial] = m_specialSort;
sortable[FieldFolder] = m_bIsFolder;
// If there's ever a need to convert more properties from CGUIListItem it might be
// worth to make CGUIListItem implement ISortable as well and call it from here
sortable[FieldLabel] = GetLabel();
if (HasMusicInfoTag())
GetMusicInfoTag()->ToSortable(sortable);
if (HasVideoInfoTag())
GetVideoInfoTag()->ToSortable(sortable);
if (HasPictureInfoTag())
GetPictureInfoTag()->ToSortable(sortable);
}
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();
return (g_settings.m_videoExtensions.Find(extension) != -1);
}
bool CFileItem::IsDiscStub() const
{
if (IsVideoDb() && HasVideoInfoTag())
{
CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder);
return dbItem.IsDiscStub();
}
CStdString strExtension;
URIUtils::GetExtension(m_strPath, strExtension);
if (strExtension.IsEmpty())
return false;
strExtension.ToLower();
strExtension += '|';
return (g_settings.m_discStubExtensions + '|').Find(strExtension) != -1;
}
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 && 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();
return (g_settings.m_musicExtensions.Find(extension) != -1);
}
bool CFileItem::IsKaraoke() const
{
if ( !IsAudio() || IsLastFM())
return false;
return CKaraokeLyricsFactory::HasLyrics( m_strPath );
}
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::IsLastFM() const
{
return URIUtils::IsLastFM(m_strPath);
}
bool CFileItem::IsInternetStream(const bool bStrictCheck /* = false */) const
{
if (HasProperty("IsHTTPDirectory"))
return false;
return URIUtils::IsInternetStream(m_strPath, bStrictCheck);
}
bool CFileItem::IsFileFolder() const
{
return (
IsSmartPlayList() ||
(IsPlayList() && g_advancedSettings.m_playlistAsFolders) ||
IsZIP() ||
IsRAR() ||
IsRSS() ||
IsType(".ogg") ||
IsType(".nsf") ||
IsType(".sid") ||
IsType(".sap")
);
}
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::IsType(const char *ext) const
{
return URIUtils::GetExtension(m_strPath).Equals(ext, false);
}
bool CFileItem::IsNFO() const
{
return URIUtils::GetExtension(m_strPath).Equals(".nfo", false);
}
bool CFileItem::IsDVDImage() const
{
CStdString strExtension;
URIUtils::GetExtension(m_strPath, strExtension);
return (strExtension.Equals(".img") || strExtension.Equals(".iso") || strExtension.Equals(".nrg"));
}
bool CFileItem::IsOpticalMediaFile() const
{
bool found = IsDVDFile(false, true);
if (found)
return true;
return IsBDFile();
}
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::IsBDFile() const
{
CStdString strFileName = URIUtils::GetFileName(m_strPath);
return (strFileName.Equals("index.bdmv"));
}
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::IsScript() const
{
return URIUtils::IsScript(m_strPath);
}
bool CFileItem::IsAddonsPath() const
{
return URIUtils::IsAddonsPath(m_strPath);
}
bool CFileItem::IsSourcesPath() const
{
return URIUtils::IsSourcesPath(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) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
}
bool CFileItem::IsOnDVD() const
{
return URIUtils::IsOnDVD(m_strPath) || m_iDriveType == CMediaSource::SOURCE_TYPE_DVD;
}
bool CFileItem::IsNfs() const
{
return URIUtils::IsNfs(m_strPath);
}
bool CFileItem::IsAfp() const
{
return URIUtils::IsAfp(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::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::IsRemovable() const
{
return IsOnDVD() || IsCDDA() || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE;
}
bool CFileItem::IsReadOnly() const
{
if (IsParentFolder()) return true;
if (m_bIsShareOrDrive) return true;
return !CUtil::SupportsFileOperations(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 ( 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);
}
}
void CFileItem::RemoveExtension()
{
if (m_bIsFolder)
return;
CStdString strLabel = GetLabel();
URIUtils::RemoveExtension(strLabel);
SetLabel(strLabel);
}
void CFileItem::CleanString()
{
if (IsLiveTV())
return;
CStdString strLabel = GetLabel();
CStdString strTitle, strTitleAndYear, strYear;
CUtil::CleanString(strLabel, strTitle, strTitleAndYear, strYear, true );
SetLabel(strTitleAndYear);
}
void CFileItem::SetLabel(const CStdString &strLabel)
{
if (strLabel=="..")
{
m_bIsParentFolder=true;
m_bIsFolder=true;
m_specialSort = SortSpecialOnTop;
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();
}
else
m_ref = CMime::GetMimeType(*this);
// 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)
{
if (item->HasProperty("item_start") || HasProperty("item_start"))
return (item->GetProperty("item_start") == GetProperty("item_start"));
return true;
}
if (IsMusicDb() && HasMusicInfoTag())
{
CFileItem dbItem(m_musicInfoTag->GetURL(), false);
dbItem.SetProperty("item_start", GetProperty("item_start"));
return dbItem.IsSamePath(item);
}
if (IsVideoDb() && HasVideoInfoTag())
{
CFileItem dbItem(m_videoInfoTag->m_strFileNameAndPath, false);
dbItem.SetProperty("item_start", GetProperty("item_start"));
return dbItem.IsSamePath(item);
}
if (item->IsMusicDb() && item->HasMusicInfoTag())
{
CFileItem dbItem(item->m_musicInfoTag->GetURL(), false);
dbItem.SetProperty("item_start", item->GetProperty("item_start"));
return IsSamePath(&dbItem);
}
if (item->IsVideoDb() && item->HasVideoInfoTag())
{
CFileItem dbItem(item->m_videoInfoTag->m_strFileNameAndPath, false);
dbItem.SetProperty("item_start", item->GetProperty("item_start"));
return IsSamePath(&dbItem);
}
if (HasProperty("original_listitem_url"))
return (GetProperty("original_listitem_url") == item->GetPath());
return false;
}
bool CFileItem::IsAlbum() const
{
return m_bIsAlbum;
}
void CFileItem::UpdateInfo(const CFileItem &item, bool replaceLabels /*=true*/)
{
if (item.HasVideoInfoTag())
{ // copy info across (TODO: premiered info is normally stored in m_dateTime by the db)
*GetVideoInfoTag() = *item.GetVideoInfoTag();
SetOverlayImage(ICON_OVERLAY_UNWATCHED, GetVideoInfoTag()->m_playCount > 0);
}
if (item.HasMusicInfoTag())
*GetMusicInfoTag() = *item.GetMusicInfoTag();
if (item.HasPictureInfoTag())
*GetPictureInfoTag() = *item.GetPictureInfoTag();
if (replaceLabels && !item.GetLabel().IsEmpty())
SetLabel(item.GetLabel());
if (replaceLabels && !item.GetLabel2().IsEmpty())
SetLabel2(item.GetLabel2());
if (!item.GetThumbnailImage().IsEmpty())
SetThumbnailImage(item.GetThumbnailImage());
if (!item.GetIconImage().IsEmpty())
SetIconImage(item.GetIconImage());
AppendProperties(item);
}
/////////////////////////////////////////////////////////////////////////////////
/////
///// CFileItemList
/////
//////////////////////////////////////////////////////////////////////////////////
CFileItemList::CFileItemList()
{
m_fastLookup = false;
m_bIsFolder = true;
m_cacheToDisc = CACHE_IF_SLOW;
m_sortMethod = SORT_METHOD_NONE;
m_sortOrder = SortOrderNone;
m_sortIgnoreFolders = false;
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 = SortOrderNone;
m_sortIgnoreFolders = false;
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];
m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), pItem));
}
}
if (!fastLookup && m_fastLookup)
m_map.clear();
m_fastLookup = fastLookup;
}
bool CFileItemList::Contains(const CStdString& fileName) const
{
CSingleLock lock(m_lock);
if (m_fastLookup)
return m_map.find(fileName) != 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(fileName))
return true;
}
return false;
}
void CFileItemList::Clear()
{
CSingleLock lock(m_lock);
ClearItems();
m_sortMethod = SORT_METHOD_NONE;
m_sortOrder = SortOrderNone;
m_sortIgnoreFolders = false;
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)
{
m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), 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)
{
m_map.insert(MAPFILEITEMSPAIR(pItem->GetPath(), 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)
{
m_map.erase(pItem->GetPath());
}
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)
{
m_map.erase(pItem->GetPath());
}
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());
SetLabel(itemlist.GetLabel());
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;
m_sortIgnoreFolders = items.m_sortIgnoreFolders;
// 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);
if (m_fastLookup)
{
IMAPFILEITEMS it=m_map.find(strPath);
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(strPath))
return pItem;
}
return CFileItemPtr();
}
const CFileItemPtr CFileItemList::Get(const CStdString& strPath) const
{
CSingleLock lock(m_lock);
if (m_fastLookup)
{
map<CStdString, CFileItemPtr>::const_iterator it=m_map.find(strPath);
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(strPath))
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);
std::stable_sort(m_items.begin(), m_items.end(), func);
}
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, SortOrder sortOrder)
{
// Already sorted?
if (sortMethod == m_sortMethod && m_sortOrder == sortOrder)
return;
SortBy sortBy = SortByNone;
SortAttribute sortAttributes = SortAttributeNone;
switch (sortMethod)
{
case SORT_METHOD_LABEL:
case SORT_METHOD_LABEL_IGNORE_FOLDERS:
case SORT_METHOD_LABEL_IGNORE_THE:
sortBy = SortByLabel;
break;
case SORT_METHOD_DATE:
sortBy = SortByDate;
break;
case SORT_METHOD_SIZE:
sortBy = SortBySize;
break;
case SORT_METHOD_BITRATE:
sortBy = SortByBitrate;
break;
case SORT_METHOD_DRIVE_TYPE:
sortBy = SortByDriveType;
break;
case SORT_METHOD_TRACKNUM:
sortBy = SortByTrackNumber;
break;
case SORT_METHOD_EPISODE:
sortBy = SortByEpisodeNumber;
break;
case SORT_METHOD_DURATION:
case SORT_METHOD_VIDEO_RUNTIME:
sortBy = SortByTime;
break;
case SORT_METHOD_TITLE:
case SORT_METHOD_TITLE_IGNORE_THE:
case SORT_METHOD_VIDEO_TITLE:
sortBy = SortByTitle;
break;
case SORT_METHOD_ARTIST:
case SORT_METHOD_ARTIST_IGNORE_THE:
sortBy = SortByArtist;
break;
case SORT_METHOD_ALBUM:
case SORT_METHOD_ALBUM_IGNORE_THE:
sortBy = SortByAlbum;
break;
case SORT_METHOD_GENRE:
sortBy = SortByGenre;
break;
case SORT_METHOD_COUNTRY:
sortBy = SortByCountry;
break;
case SORT_METHOD_DATEADDED:
sortBy = SortByDateAdded;
break;
case SORT_METHOD_FILE:
sortBy = SortByFile;
break;
case SORT_METHOD_SONG_RATING:
case SORT_METHOD_VIDEO_RATING:
sortBy = SortByRating;
break;
case SORT_METHOD_VIDEO_SORT_TITLE:
case SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE:
sortBy = SortBySortTitle;
break;
case SORT_METHOD_YEAR:
sortBy = SortByYear;
break;
case SORT_METHOD_PRODUCTIONCODE:
sortBy = SortByProductionCode;
break;
case SORT_METHOD_PROGRAM_COUNT:
sortBy = SortByProgramCount;
break;
case SORT_METHOD_PLAYLIST_ORDER:
sortBy = SortByPlaylistOrder;
break;
case SORT_METHOD_MPAA_RATING:
sortBy = SortByMPAA;
break;
case SORT_METHOD_STUDIO:
case SORT_METHOD_STUDIO_IGNORE_THE:
sortBy = SortByStudio;
break;
case SORT_METHOD_FULLPATH:
sortBy = SortByPath;
break;
case SORT_METHOD_LASTPLAYED:
sortBy = SortByLastPlayed;
break;
case SORT_METHOD_PLAYCOUNT:
sortBy = SortByPlaycount;
break;
case SORT_METHOD_LISTENERS:
sortBy = SortByListeners;
break;
default:
CLog::Log(LOGWARNING, "Unknown sort method %d", sortMethod);
return;
}
if (sortMethod == SORT_METHOD_LABEL_IGNORE_THE ||
sortMethod == SORT_METHOD_TITLE_IGNORE_THE ||
sortMethod == SORT_METHOD_ARTIST_IGNORE_THE ||
sortMethod == SORT_METHOD_ALBUM_IGNORE_THE ||
sortMethod == SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE ||
sortMethod == SORT_METHOD_STUDIO_IGNORE_THE)
sortAttributes = (SortAttribute)((int)sortAttributes | SortAttributeIgnoreArticle);
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 ||
sortMethod == SORT_METHOD_DATEADDED ||
sortMethod == SORT_METHOD_VIDEO_RATING ||
sortMethod == SORT_METHOD_YEAR ||
sortMethod == SORT_METHOD_PLAYLIST_ORDER ||
sortMethod == SORT_METHOD_LASTPLAYED ||
sortMethod == SORT_METHOD_PLAYCOUNT ||
m_sortIgnoreFolders)
sortAttributes = (SortAttribute)((int)sortAttributes | SortAttributeIgnoreFolders);
if (sortBy == SortByNone)
return;
SortItems sortItems((size_t)Size());
for (int index = 0; index < Size(); index++)
{
m_items[index]->ToSortable(sortItems[index]);
sortItems[index][FieldId] = index;
}
// do the sorting
SortUtils::Sort(sortBy, sortOrder, sortAttributes, sortItems);
// apply the new order to the existing CFileItems
VECFILEITEMS sortedFileItems;
sortedFileItems.reserve(Size());
for (SortItems::const_iterator it = sortItems.begin(); it != sortItems.end(); it++)
{
CFileItemPtr item = m_items[(int)it->at(FieldId).asInteger()];
// Set the sort label in the CFileItem
item->SetSortLabel(CStdStringW(it->at(FieldSort).asWideString()));
sortedFileItems.push_back(item);
}
// replace the current list with the re-ordered one
m_items.assign(sortedFileItems.begin(), sortedFileItems.end());
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 << m_sortIgnoreFolders;
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 = SortOrder(tempint);
ar >> m_sortIgnoreFolders;
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();
}
}
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.albumArtist.empty() && !tag.GetAlbumArtist().empty()) song.albumArtist = tag.GetAlbumArtist();
if (song.genre.empty() && !tag.GetGenre().empty()) song.genre = tag.GetGenre();
if (song.artist.empty() && !tag.GetArtist().empty()) song.artist = 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.embeddedArt.empty() && !tag.GetCoverArtInfo().empty())
song.embeddedArt = tag.GetCoverArtInfo();
}
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(bool stackFiles /* = true */)
{
CSingleLock lock(m_lock);
// not allowed here
if (IsVirtualDirectoryRoot() || IsLiveTV() || IsSourcesPath())
return;
SetProperty("isstacked", true);
// items needs to be sorted for stuff below to work properly
Sort(SORT_METHOD_LABEL, SortOrderAscending);
StackFolders();
if (stackFiles)
StackFiles();
}
void CFileItemList::StackFolders()
{
// Precompile our REs
VECCREGEXP folderRegExps;
CRegExp folderRegExp(true);
const CStdStringArray& strFolderRegExps = g_advancedSettings.m_folderStackRegExps;
CStdStringArray::const_iterator strExpression = strFolderRegExps.begin();
while (strExpression != strFolderRegExps.end())
{
if (!folderRegExp.RegComp(*strExpression))
CLog::Log(LOGERROR, "%s: Invalid folder stack RegExp:'%s'", __FUNCTION__, strExpression->c_str());
else
folderRegExps.push_back(folderRegExp);
strExpression++;
}
// stack folders
for (int i = 0; i < Size(); i++)
{
CFileItemPtr item = Get(i);
// combined the folder checks
if (item->m_bIsFolder)
{
// only check known fast sources?
// NOTES:
// 1. rars and zips may be on slow sources? is this supposed to be allowed?
if( !item->IsRemote()
|| item->IsSmb()
|| item->IsNfs()
|| item->IsAfp()
|| URIUtils::IsInRAR(item->GetPath())
|| URIUtils::IsInZIP(item->GetPath())
|| URIUtils::IsOnLAN(item->GetPath())
)
{
// stack cd# folders if contains only a single video file
bool bMatch(false);
VECCREGEXP::iterator expr = folderRegExps.begin();
while (!bMatch && expr != folderRegExps.end())
{
//CLog::Log(LOGDEBUG,"%s: Running expression %s on %s", __FUNCTION__, expr->GetPattern().c_str(), item->GetLabel().c_str());
bMatch = (expr->RegFind(item->GetLabel().c_str()) != -1);
if (bMatch)
{
CFileItemList items;
CDirectory::GetDirectory(item->GetPath(),items,g_settings.m_videoExtensions);
// 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];
}
expr++;
}
// check for dvd folders
if (!bMatch)
{
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;
}
#ifdef HAVE_LIBBLURAY
if (dvdPath.IsEmpty())
{
URIUtils::AddFileToFolder(item->GetPath(), "index.bdmv", path);
if (CFile::Exists(path))
dvdPath = path;
else
{
URIUtils::AddFileToFolder(item->GetPath(), "BDMV", dvdPath);
URIUtils::AddFileToFolder(dvdPath, "index.bdmv", path);
dvdPath.Empty();
if (CFile::Exists(path))
dvdPath = path;
}
}
#endif
if (!dvdPath.IsEmpty())
{
// NOTE: should this be done for the CD# folders too?
item->m_bIsFolder = false;
item->SetPath(dvdPath);
item->SetLabel2("");
item->SetLabelPreformated(true);
m_sortMethod = SORT_METHOD_NONE; /* sorting is now broken */
}
}
}
}
}
}
void CFileItemList::StackFiles()
{
// 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
int i = 0;
while (i < Size())
{
CFileItemPtr item1 = Get(i);
// 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);
if (URIUtils::ProtocolHasEncodedFilename(CURL(filePath).GetProtocol() ) )
CURL::Decode(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 (URIUtils::ProtocolHasEncodedFilename(CURL(filePath2).GetProtocol() ) )
CURL::Decode(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);
item1->SetLabel(stackName);
item1->m_dwSize = size;
break;
}
}
i++;
}
}
bool CFileItemList::Load(int windowID)
{
CFile file;
if (file.Open(GetDiscFileCache(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(GetDiscFileCache(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(GetDiscFileCache(windowID));
if (CFile::Exists(cacheFile))
{
CLog::Log(LOGDEBUG,"Clearing cached fileitems [%s]",GetPath().c_str());
CFile::Delete(cacheFile);
}
}
CStdString CFileItemList::GetDiscFileCache(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 (IsSmartPlayList())
cacheFile.Format("special://temp/sp-%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;
}
CStdString CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */) const
{
if (m_strPath.IsEmpty()
|| m_bIsShareOrDrive
|| IsInternetStream()
|| URIUtils::IsUPnP(m_strPath)
|| (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
|| IsPlugin()
|| IsAddonsPath()
|| 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;
}
}
}
// No thumb found
return "";
}
// 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)
|| (URIUtils::IsFTP(m_strPath) && !g_advancedSettings.m_bFTPThumbs)
|| IsPlugin()
|| IsAddonsPath()
|| IsParentFolder()
|| IsLiveTV()
|| IsDVD())
return "";
// 1. check <filename>.tbn or <foldername>.tbn
CStdString fileThumb(GetTBNFile());
if (CFile::Exists(fileThumb))
return fileThumb;
if (IsOpticalMediaFile())
{ // special case for optical media "folders" - check the parent folder (or parent of parent)
// TODO: A better way to handle this would be to treat stacked folders as folders rather than files.
CFileItem item(GetLocalMetadataPath(), true);
CStdString thumb(item.GetUserVideoThumb());
if (!thumb.IsEmpty())
return thumb;
}
// 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 = GetBaseMoviePath(bUseFolderNames);
if (URIUtils::IsStack(strMovieName))
strMovieName = CStackDirectory::GetStackedTitlePath(strMovieName);
URIUtils::RemoveSlashAtEnd(strMovieName);
strMovieName = URIUtils::GetFileName(strMovieName);
CURL::Decode(strMovieName);
return strMovieName;
}
CStdString CFileItem::GetBaseMoviePath(bool bUseFolderNames) const
{
CStdString strMovieName = m_strPath;
if (IsMultiPath())
strMovieName = CMultiPathDirectory::GetFirstPath(m_strPath);
if (IsOpticalMediaFile())
return GetLocalMetadataPath();
if ((!m_bIsFolder || URIUtils::IsInArchive(m_strPath)) && bUseFolderNames)
{
CStdString name2(strMovieName);
URIUtils::GetParentPath(name2,strMovieName);
if (URIUtils::IsInArchive(m_strPath))
{
CStdString strArchivePath;
URIUtils::GetParentPath(strMovieName, strArchivePath);
strMovieName = strArchivePath;
}
}
return strMovieName;
}
#ifdef UNIT_TESTING
bool CFileItem::testGetBaseMoviePath()
{
typedef struct
{
const char *file;
bool use_folder;
const char *base;
} testfiles;
const testfiles test_files[] = {{ "c:\\dir\\filename.avi", false, "c:\\dir\\filename.avi" },
{ "c:\\dir\\filename.avi", true, "c:\\dir\\" },
{ "/dir/filename.avi", false, "/dir/filename.avi" },
{ "/dir/filename.avi", true, "/dir/" },
{ "smb://somepath/file.avi", false, "smb://somepath/file.avi" },
{ "smb://somepath/file.avi", true, "smb://somepath/" },
{ "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" },
{ "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi", true, "/path/to/movie_name/" },
{ "/home/user/TV Shows/Dexter/S1/1x01.avi", false, "/home/user/TV Shows/Dexter/S1/1x01.avi" },
{ "/home/user/TV Shows/Dexter/S1/1x01.avi", true, "/home/user/TV Shows/Dexter/S1/" },
{ "rar://g%3a%5cmultimedia%5cmovies%5cSphere%2erar/Sphere.avi", true, "g:\\multimedia\\movies\\" },
{ "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", false, "/home/user/movies/movie_name/" },
{ "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", true, "/home/user/movies/movie_name/" },
{ "/home/user/movies/movie_name/BDMV/index.bdmv", false, "/home/user/movies/movie_name/" },
{ "/home/user/movies/movie_name/BDMV/index.bdmv", true, "/home/user/movies/movie_name/" }};
for (unsigned int i = 0; i < sizeof(test_files) / sizeof(testfiles); i++)
{
CFileItem item;
item.SetPath(test_files[i].file);
CStdString path = item.GetBaseMoviePath(test_files[i].use_folder);
if (path != test_files[i].base)
{
CLog::Log(LOGFATAL, "%s failed ('%s' -> '%s' != '%s')", __FUNCTION__, test_files[i].file, path.c_str(), test_files[i].base);
return false;
}
}
return true;
}
#endif
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)
|| URIUtils::IsBluray(strFile)
|| IsLiveTV()
|| IsPlugin()
|| IsAddonsPath()
|| IsDVD()
|| (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, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
if (IsOpticalMediaFile())
{ // grab from the optical media parent folder as well - see GetUserVideoThumb
CFileItemList moreItems;
CDirectory::GetDirectory(GetLocalMetadataPath(), moreItems, g_settings.m_pictureExtensions, DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
items.Append(moreItems);
}
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::GetLocalMetadataPath() const
{
if (m_bIsFolder && !IsFileFolder())
return m_strPath;
CStdString parent(URIUtils::GetParentPath(m_strPath));
CStdString parentFolder(parent);
URIUtils::RemoveSlashAtEnd(parentFolder);
parentFolder = URIUtils::GetFileName(parentFolder);
if (parentFolder.CompareNoCase("VIDEO_TS") == 0 || parentFolder.CompareNoCase("BDMV") == 0)
{ // go back up another one
parent = URIUtils::GetParentPath(parent);
}
return parent;
}
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 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;
CSingleLock lock(m_lock);
for (unsigned int i = 0; i < m_items.size(); i++)
{
CFileItemPtr pItem = m_items[i];
if (pItem->IsSamePath(item))
{
*pItem = *item;
return true;
}
}
return false;
}
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 = SortOrderNone;
}
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)
|| URIUtils::IsBluray(strFile)
|| IsLiveTV()
|| IsPlugin()
|| IsDVD())
return "";
CStdString strDir;
URIUtils::GetDirectory(strFile, strDir);
CFileItemList items;
CDirectory::GetDirectory(strDir, items, g_settings.m_videoExtensions, DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);
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;
}
int 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_artist.empty())
type = VIDEODB_CONTENT_MUSICVIDEOS;
return type;
}
Jump to Line
Something went wrong with that request. Please try again.