std::string CSmartPlaylistDirectory::GetPlaylistByName(const std::string& name, const std::string& playlistType) { CFileItemList list; bool filesExist = false; if (CSmartPlaylist::IsMusicType(playlistType)) filesExist = CDirectory::GetDirectory("special://musicplaylists/", list, ".xsp", false); else // all others are video filesExist = CDirectory::GetDirectory("special://videoplaylists/", list, ".xsp", false); if (filesExist) { for (int i = 0; i < list.Size(); i++) { CFileItemPtr item = list[i]; CSmartPlaylist playlist; if (playlist.OpenAndReadName(item->GetURL())) { if (StringUtils::EqualsNoCase(playlist.GetName(), name)) return item->GetPath(); } } for (int i = 0; i < list.Size(); i++) { // check based on filename CFileItemPtr item = list[i]; if (URIUtils::GetFileName(item->GetPath()) == name) { // found :) return item->GetPath(); } } } return ""; }
CStdString CSmartPlaylistDirectory::GetPlaylistByName(const CStdString& name, const CStdString& playlistType) { CFileItemList list; bool filesExist = false; if (playlistType == "songs" || playlistType == "albums") filesExist = CDirectory::GetDirectory("special://musicplaylists/", list, ".xsp", false); else // all others are video filesExist = CDirectory::GetDirectory("special://videoplaylists/", list, ".xsp", false); if (filesExist) { for (int i = 0; i < list.Size(); i++) { CFileItemPtr item = list[i]; CSmartPlaylist playlist; if (playlist.OpenAndReadName(item->GetPath())) { if (playlist.GetName().CompareNoCase(name) == 0) return item->GetPath(); } } for (int i = 0; i < list.Size(); i++) { // check based on filename CFileItemPtr item = list[i]; if (URIUtils::GetFileName(item->GetPath()) == name) { // found :) return item->GetPath(); } } } return ""; }
void CGUIDialogSmartPlaylistRule::OnBrowse() { CFileItemList items; CMusicDatabase database; database.Open(); CVideoDatabase videodatabase; videodatabase.Open(); VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES; if (m_type.Equals("tvshows")) type = VIDEODB_CONTENT_TVSHOWS; else if (m_type.Equals("musicvideos")) type = VIDEODB_CONTENT_MUSICVIDEOS; else if (m_type.Equals("episodes")) type = VIDEODB_CONTENT_EPISODES; int iLabel = 0; if (m_rule.m_field == FieldGenre) { if (m_type.Equals("tvshows") || m_type.Equals("episodes") || m_type.Equals("movies")) videodatabase.GetGenresNav("videodb://2/1/",items,type); else if (m_type.Equals("songs") || m_type.Equals("albums") || m_type.Equals("artists") || m_type.Equals("mixed")) database.GetGenresNav("musicdb://1/",items); if (m_type.Equals("musicvideos") || m_type.Equals("mixed")) { CFileItemList items2; videodatabase.GetGenresNav("videodb://3/1/",items2,VIDEODB_CONTENT_MUSICVIDEOS); items.Append(items2); } iLabel = 515; } else if (m_rule.m_field == FieldCountry) { videodatabase.GetCountriesNav("videodb://2/1/",items,type); iLabel = 574; } else if (m_rule.m_field == FieldArtist || m_rule.m_field == FieldAlbumArtist) { if (m_type.Equals("songs") || m_type.Equals("mixed") || m_type.Equals("albums") || m_type.Equals("artists")) database.GetArtistsNav("musicdb://2/", items, m_rule.m_field == FieldAlbumArtist, -1); if (m_type.Equals("musicvideos") || m_type.Equals("mixed")) { CFileItemList items2; videodatabase.GetMusicVideoArtistsByName("",items2); items.Append(items2); } iLabel = 557; } else if (m_rule.m_field == FieldAlbum) { if (m_type.Equals("songs") || m_type.Equals("mixed") || m_type.Equals("albums")) database.GetAlbumsNav("musicdb://3/", items); if (m_type.Equals("musicvideos") || m_type.Equals("mixed")) { CFileItemList items2; videodatabase.GetMusicVideoAlbumsByName("",items2); items.Append(items2); } iLabel = 558; } else if (m_rule.m_field == FieldActor) { videodatabase.GetActorsNav("",items,type); iLabel = 20337; } else if (m_rule.m_field == FieldYear) { if (m_type.Equals("songs") || m_type.Equals("mixed") || m_type.Equals("albums")) database.GetYearsNav("musicdb://9/", items); if (!m_type.Equals("songs") && !m_type.Equals("albums")) { CFileItemList items2; videodatabase.GetYearsNav("", items2, type); items.Append(items2); } iLabel = 562; } else if (m_rule.m_field == FieldDirector) { videodatabase.GetDirectorsNav("",items,type); iLabel = 20339; } else if (m_rule.m_field == FieldStudio) { videodatabase.GetStudiosNav("",items,type); iLabel = 572; } else if (m_rule.m_field == FieldWriter) { videodatabase.GetWritersNav("",items,type); iLabel = 20417; } else if (m_rule.m_field == FieldTvShowTitle) { videodatabase.GetTvShowsNav("videodb://2/2/",items); iLabel = 20343; } else if (m_rule.m_field == FieldPlaylist) { // use filebrowser to grab another smart playlist // Note: This can cause infinite loops (playlist that refers to the same playlist) but I don't // think there's any decent way to deal with this, as the infinite loop may be an arbitrary // number of playlists deep, eg playlist1 -> playlist2 -> playlist3 ... -> playlistn -> playlist1 CStdString path = "special://videoplaylists/"; if (m_type.Equals("songs") || m_type.Equals("albums")) path = "special://musicplaylists/"; XFILE::CDirectory::GetDirectory(path, items, ".xsp", XFILE::DIR_FLAG_NO_FILE_DIRS); for (int i = 0; i < items.Size(); i++) { CFileItemPtr item = items[i]; CSmartPlaylist playlist; if (playlist.OpenAndReadName(item->GetPath())) item->SetLabel(playlist.GetName()); } iLabel = 559; } else if (m_rule.m_field == FieldPath) { VECSOURCES sources; if (m_type == "songs" || m_type == "mixed") sources = *g_settings.GetSourcesFromType("music"); if (m_type != "songs") { VECSOURCES sources2 = *g_settings.GetSourcesFromType("video"); sources.insert(sources.end(),sources2.begin(),sources2.end()); } g_mediaManager.GetLocalDrives(sources); CStdString path = m_rule.GetLocalizedParameter(m_type); CGUIDialogFileBrowser::ShowAndGetDirectory(sources, g_localizeStrings.Get(657), path, false); if (m_rule.m_parameter.size() > 0) m_rule.m_parameter.clear(); if (!path.empty()) m_rule.m_parameter.push_back(path); UpdateButtons(); return; } else if (m_rule.m_field == FieldSet) { videodatabase.GetSetsNav("videodb://1/7/", items, VIDEODB_CONTENT_MOVIES); iLabel = 20434; } else if (m_rule.m_field == FieldTag) { if (m_type == "movies") videodatabase.GetTagsNav("videodb://1/9/", items, VIDEODB_CONTENT_MOVIES); else return; iLabel = 20459; } else { // TODO: Add browseability in here. assert(false); } // sort the items items.Sort(SORT_METHOD_LABEL, SortOrderAscending); CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); pDialog->Reset(); pDialog->SetItems(&items); CStdString strHeading; strHeading.Format(g_localizeStrings.Get(13401),g_localizeStrings.Get(iLabel)); pDialog->SetHeading(strHeading); pDialog->SetMultiSelection(true); if (!m_rule.m_parameter.empty()) pDialog->SetSelected(m_rule.m_parameter); pDialog->DoModal(); if (pDialog->IsConfirmed()) { const CFileItemList &items = pDialog->GetSelectedItems(); m_rule.m_parameter.clear(); for (int index = 0; index < items.Size(); index++) m_rule.m_parameter.push_back(items[index]->GetLabel()); UpdateButtons(); } pDialog->Reset(); }
// return NULL + set pItem->m_bIsFolder to remove it completely from list. IFileDirectory* CFileDirectoryFactory::Create(const CStdString& strPath, CFileItem* pItem, const CStdString& strMask) { if (URIUtils::IsStack(strPath)) // disqualify stack as we need to work with each of the parts instead return NULL; CStdString strExtension=URIUtils::GetExtension(strPath); StringUtils::ToLower(strExtension); #ifdef HAS_FILESYSTEM if ((strExtension.Equals(".ogg") || strExtension.Equals(".oga")) && CFile::Exists(strPath)) { IFileDirectory* pDir=new COGGFileDirectory; // Has the ogg file more than one bitstream? if (pDir->ContainsFiles(strPath)) { return pDir; // treat as directory } delete pDir; return NULL; } if (strExtension.Equals(".nsf") && CFile::Exists(strPath)) { IFileDirectory* pDir=new CNSFFileDirectory; // Has the nsf file more than one track? if (pDir->ContainsFiles(strPath)) return pDir; // treat as directory delete pDir; return NULL; } if (strExtension.Equals(".sid") && CFile::Exists(strPath)) { IFileDirectory* pDir=new CSIDFileDirectory; // Has the sid file more than one track? if (pDir->ContainsFiles(strPath)) return pDir; // treat as directory delete pDir; return NULL; } #ifdef HAS_ASAP_CODEC if (ASAPCodec::IsSupportedFormat(strExtension) && CFile::Exists(strPath)) { IFileDirectory* pDir=new CASAPFileDirectory; // Has the asap file more than one track? if (pDir->ContainsFiles(strPath)) return pDir; // treat as directory delete pDir; return NULL; } #endif if (pItem->IsRSS()) return new CRSSDirectory(); if (pItem->IsDVDImage()) return new CUDFDirectory(); #endif #if defined(TARGET_ANDROID) if (strExtension.Equals(".apk")) { CStdString strUrl; URIUtils::CreateArchivePath(strUrl, "apk", strPath, ""); CFileItemList items; CDirectory::GetDirectory(strUrl, items, strMask); if (items.Size() == 0) // no files pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0) { // one STORED file - collapse it down *pItem = *items[0]; } else { // compressed or more than one file -> create a apk dir pItem->SetPath(strUrl); return new CAPKDirectory; } return NULL; } #endif if (strExtension.Equals(".zip")) { CStdString strUrl; URIUtils::CreateArchivePath(strUrl, "zip", strPath, ""); CFileItemList items; CDirectory::GetDirectory(strUrl, items, strMask); if (items.Size() == 0) // no files pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0) { // one STORED file - collapse it down *pItem = *items[0]; } else { // compressed or more than one file -> create a zip dir pItem->SetPath(strUrl); return new CZipDirectory; } return NULL; } if (strExtension.Equals(".rar") || strExtension.Equals(".001")) { CStdString strUrl; URIUtils::CreateArchivePath(strUrl, "rar", strPath, ""); vector<std::string> tokens; StringUtils::Tokenize(strPath,tokens,"."); if (tokens.size() > 2) { if (strExtension.Equals(".001")) { if (StringUtils::EqualsNoCase(tokens[tokens.size()-2], "ts")) // .ts.001 - treat as a movie file to scratch some users itch return NULL; } CStdString token = tokens[tokens.size()-2]; if (StringUtils::StartsWithNoCase(token, "part")) // only list '.part01.rar' { // need this crap to avoid making mistakes - yeyh for the new rar naming scheme :/ struct __stat64 stat; int digits = token.size()-4; CStdString strFormat = StringUtils::Format("part%%0%ii", digits); CStdString strNumber = StringUtils::Format(strFormat.c_str(), 1); CStdString strPath2 = strPath; StringUtils::Replace(strPath2,token,strNumber); if (atoi(token.substr(4).c_str()) > 1 && CFile::Stat(strPath2,&stat) == 0) { pItem->m_bIsFolder = true; return NULL; } } } CFileItemList items; CDirectory::GetDirectory(strUrl, items, strMask); if (items.Size() == 0) // no files - hide this pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0x30) { // one STORED file - collapse it down *pItem = *items[0]; } else { #ifdef HAS_FILESYSTEM_RAR // compressed or more than one file -> create a rar dir pItem->SetPath(strUrl); return new CRarDirectory; #else return NULL; #endif } return NULL; } if (strExtension.Equals(".xsp")) { // XBMC Smart playlist - just XML renamed to XSP // read the name of the playlist in CSmartPlaylist playlist; if (playlist.OpenAndReadName(strPath)) { pItem->SetLabel(playlist.GetName()); pItem->SetLabelPreformated(true); } IFileDirectory* pDir=new CSmartPlaylistDirectory; return pDir; // treat as directory } if (CPlayListFactory::IsPlaylist(strPath)) { // Playlist file // currently we only return the directory if it contains // more than one file. Reason is that .pls and .m3u may be used // for links to http streams etc. IFileDirectory *pDir = new CPlaylistFileDirectory(); CFileItemList items; if (pDir->GetDirectory(strPath, items)) { if (items.Size() > 1) return pDir; } delete pDir; return NULL; } return NULL; }
// return NULL + set pItem->m_bIsFolder to remove it completely from list. IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, const std::string& strMask) { if (url.IsProtocol("stack")) // disqualify stack as we need to work with each of the parts instead return NULL; std::string strExtension=URIUtils::GetExtension(url); StringUtils::ToLower(strExtension); if (!strExtension.empty()) { VECADDONS codecs; CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); addonCache.GetAddons(codecs, ADDON_AUDIODECODER); for (size_t i=0;i<codecs.size();++i) { std::shared_ptr<CAudioDecoder> dec(std::static_pointer_cast<CAudioDecoder>(codecs[i])); if (dec->HasTracks() && dec->GetExtensions().find(strExtension) != std::string::npos) { CAudioDecoder* result = new CAudioDecoder(*dec); result->Create(); if (result->ContainsFiles(url)) return result; delete result; return NULL; } } } if (CServiceBroker::IsBinaryAddonCacheUp()) { VECADDONS vfs; CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); addonCache.GetAddons(vfs, ADDON_VFS); for (size_t i=0;i<vfs.size();++i) { std::shared_ptr<CVFSEntry> dec(std::static_pointer_cast<CVFSEntry>(vfs[i])); if (!strExtension.empty() && dec->HasFileDirectories() && dec->GetExtensions().find(strExtension) != std::string::npos) { CVFSEntryIFileDirectoryWrapper* wrap = new CVFSEntryIFileDirectoryWrapper(dec); if (wrap->ContainsFiles(url)) { if (wrap->m_items.Size() == 1) { // one STORED file - collapse it down *pItem = *wrap->m_items[0]; } else { // compressed or more than one file -> create a dir pItem->SetPath(wrap->m_items.GetPath()); return wrap; } } else pItem->m_bIsFolder = true; delete wrap; return NULL; } } } if (pItem->IsRSS()) return new CRSSDirectory(); if (pItem->IsDiscImage()) return new CUDFDirectory(); #if defined(TARGET_ANDROID) if (url.IsFileType("apk")) { CURL zipURL = URIUtils::CreateArchivePath("apk", url); CFileItemList items; CDirectory::GetDirectory(zipURL, items, strMask); if (items.Size() == 0) // no files pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder) { // one STORED file - collapse it down *pItem = *items[0]; } else { // compressed or more than one file -> create a apk dir pItem->SetURL(zipURL); return new CAPKDirectory; } return NULL; } #endif if (url.IsFileType("zip")) { CURL zipURL = URIUtils::CreateArchivePath("zip", url); CFileItemList items; CDirectory::GetDirectory(zipURL, items, strMask); if (items.Size() == 0) // no files pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder) { // one STORED file - collapse it down *pItem = *items[0]; } else { // compressed or more than one file -> create a zip dir pItem->SetURL(zipURL); return new CZipDirectory; } return NULL; } if (url.IsFileType("rar") || url.IsFileType("001")) { std::vector<std::string> tokens; const std::string strPath = url.Get(); StringUtils::Tokenize(strPath,tokens,"."); if (tokens.size() > 2) { if (url.IsFileType("001")) { if (StringUtils::EqualsNoCase(tokens[tokens.size()-2], "ts")) // .ts.001 - treat as a movie file to scratch some users itch return NULL; } std::string token = tokens[tokens.size()-2]; if (StringUtils::StartsWith(token, "part")) // only list '.part01.rar' { // need this crap to avoid making mistakes - yeyh for the new rar naming scheme :/ struct __stat64 stat; int digits = token.size()-4; std::string strFormat = StringUtils::Format("part%%0%ii", digits); std::string strNumber = StringUtils::Format(strFormat.c_str(), 1); std::string strPath2 = strPath; StringUtils::Replace(strPath2,token,strNumber); if (atoi(token.substr(4).c_str()) > 1 && CFile::Stat(strPath2,&stat) == 0) { pItem->m_bIsFolder = true; return NULL; } } } CURL rarURL = URIUtils::CreateArchivePath("rar", url); CFileItemList items; CDirectory::GetDirectory(rarURL, items, strMask); if (items.Size() == 0) // no files - hide this pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0x30 && !items[0]->m_bIsFolder) { // one STORED file - collapse it down *pItem = *items[0]; } else { #ifdef HAS_FILESYSTEM_RAR // compressed or more than one file -> create a rar dir pItem->SetURL(rarURL); return new CRarDirectory; #else return NULL; #endif } return NULL; } if (url.IsFileType("xbt")) { CURL xbtUrl = URIUtils::CreateArchivePath("xbt", url); pItem->SetURL(xbtUrl); return new CXbtDirectory(); } if (url.IsFileType("xsp")) { // XBMC Smart playlist - just XML renamed to XSP // read the name of the playlist in CSmartPlaylist playlist; if (playlist.OpenAndReadName(url)) { pItem->SetLabel(playlist.GetName()); pItem->SetLabelPreformatted(true); } IFileDirectory* pDir=new CSmartPlaylistDirectory; return pDir; // treat as directory } if (CPlayListFactory::IsPlaylist(url)) { // Playlist file // currently we only return the directory if it contains // more than one file. Reason is that .pls and .m3u may be used // for links to http streams etc. IFileDirectory *pDir = new CPlaylistFileDirectory(); CFileItemList items; if (pDir->GetDirectory(url, items)) { if (items.Size() > 1) return pDir; } delete pDir; return NULL; } if (pItem->IsAudioBook()) { if (!pItem->HasMusicInfoTag() || pItem->m_lEndOffset <= 0) { std::unique_ptr<CAudioBookFileDirectory> pDir(new CAudioBookFileDirectory); if (pDir->ContainsFiles(url)) return pDir.release(); } return NULL; } return NULL; }
// return NULL + set pItem->m_bIsFolder to remove it completely from list. IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, const std::string& strMask) { if (url.IsProtocol("stack")) // disqualify stack as we need to work with each of the parts instead return NULL; std::string strExtension=URIUtils::GetExtension(url); StringUtils::ToLower(strExtension); if (!strExtension.empty() && CServiceBroker::IsBinaryAddonCacheUp()) { BinaryAddonBaseList addonInfos; CServiceBroker::GetBinaryAddonManager().GetAddonInfos(addonInfos, true, ADDON_AUDIODECODER); for (const auto& addonInfo : addonInfos) { if (CAudioDecoder::HasTracks(addonInfo) && CAudioDecoder::GetExtensions(addonInfo).find(strExtension) != std::string::npos) { CAudioDecoder* result = new CAudioDecoder(addonInfo); if (!result->CreateDecoder() || !result->ContainsFiles(url)) { delete result; return nullptr; } return result; } } } if (!strExtension.empty() && CServiceBroker::IsBinaryAddonCacheUp()) { for (const auto& vfsAddon : CServiceBroker::GetVFSAddonCache().GetAddonInstances()) { if (vfsAddon->HasFileDirectories() && vfsAddon->GetExtensions().find(strExtension) != std::string::npos) { CVFSEntryIFileDirectoryWrapper* wrap = new CVFSEntryIFileDirectoryWrapper(vfsAddon); if (wrap->ContainsFiles(url)) { if (wrap->m_items.Size() == 1) { // one STORED file - collapse it down *pItem = *wrap->m_items[0]; } else { // compressed or more than one file -> create a dir pItem->SetPath(wrap->m_items.GetPath()); return wrap; } } else pItem->m_bIsFolder = true; delete wrap; return nullptr; } } } if (pItem->IsRSS()) return new CRSSDirectory(); if (pItem->IsDiscImage()) return new CUDFDirectory(); #if defined(TARGET_ANDROID) if (url.IsFileType("apk")) { CURL zipURL = URIUtils::CreateArchivePath("apk", url); CFileItemList items; CDirectory::GetDirectory(zipURL, items, strMask); if (items.Size() == 0) // no files pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder) { // one STORED file - collapse it down *pItem = *items[0]; } else { // compressed or more than one file -> create a apk dir pItem->SetURL(zipURL); return new CAPKDirectory; } return NULL; } #endif if (url.IsFileType("zip")) { CURL zipURL = URIUtils::CreateArchivePath("zip", url); CFileItemList items; CDirectory::GetDirectory(zipURL, items, strMask); if (items.Size() == 0) // no files pItem->m_bIsFolder = true; else if (items.Size() == 1 && items[0]->m_idepth == 0 && !items[0]->m_bIsFolder) { // one STORED file - collapse it down *pItem = *items[0]; } else { // compressed or more than one file -> create a zip dir pItem->SetURL(zipURL); return new CZipDirectory; } return NULL; } if (url.IsFileType("xbt")) { CURL xbtUrl = URIUtils::CreateArchivePath("xbt", url); pItem->SetURL(xbtUrl); return new CXbtDirectory(); } if (url.IsFileType("xsp")) { // XBMC Smart playlist - just XML renamed to XSP // read the name of the playlist in CSmartPlaylist playlist; if (playlist.OpenAndReadName(url)) { pItem->SetLabel(playlist.GetName()); pItem->SetLabelPreformatted(true); } IFileDirectory* pDir=new CSmartPlaylistDirectory; return pDir; // treat as directory } if (CPlayListFactory::IsPlaylist(url)) { // Playlist file // currently we only return the directory if it contains // more than one file. Reason is that .pls and .m3u may be used // for links to http streams etc. IFileDirectory *pDir = new CPlaylistFileDirectory(); CFileItemList items; if (pDir->GetDirectory(url, items)) { if (items.Size() > 1) return pDir; } delete pDir; return NULL; } if (pItem->IsAudioBook()) { if (!pItem->HasMusicInfoTag() || pItem->m_lEndOffset <= 0) { std::unique_ptr<CAudioBookFileDirectory> pDir(new CAudioBookFileDirectory); if (pDir->ContainsFiles(url)) return pDir.release(); } return NULL; } return NULL; }