/* * Copyright (C) 2005-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #include "GUIWindowMusicNav.h" #include "FileItem.h" #include "GUIPassword.h" #include "GUIUserMessages.h" #include "PartyModeManager.h" #include "ServiceBroker.h" #include "URL.h" #include "Util.h" #include "addons/AddonSystemSettings.h" #include "dialogs/GUIDialogYesNo.h" #include "filesystem/MusicDatabaseDirectory.h" #include "filesystem/VideoDatabaseDirectory.h" #include "guilib/GUIComponent.h" #include "guilib/GUIEditControl.h" #include "guilib/GUIKeyboardFactory.h" #include "guilib/GUIWindowManager.h" #include "guilib/LocalizeStrings.h" #include "input/Key.h" #include "messaging/ApplicationMessenger.h" #include "messaging/helpers/DialogOKHelper.h" #include "music/MusicLibraryQueue.h" #include "music/dialogs/GUIDialogInfoProviderSettings.h" #include "music/tags/MusicInfoTag.h" #include "playlists/PlayList.h" #include "playlists/PlayListFactory.h" #include "profiles/ProfileManager.h" #include "settings/AdvancedSettings.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "storage/MediaManager.h" #include "utils/FileUtils.h" #include "utils/LegacyPathTranslation.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" #include "utils/Variant.h" #include "utils/log.h" #include "video/VideoDatabase.h" #include "video/dialogs/GUIDialogVideoInfo.h" #include "video/windows/GUIWindowVideoNav.h" #include "view/GUIViewState.h" using namespace XFILE; using namespace PLAYLIST; using namespace MUSICDATABASEDIRECTORY; using namespace KODI::MESSAGING; #define CONTROL_BTNVIEWASICONS 2 #define CONTROL_BTNSORTBY 3 #define CONTROL_BTNSORTASC 4 #define CONTROL_BTNTYPE 5 #define CONTROL_LABELFILES 12 #define CONTROL_SEARCH 8 #define CONTROL_FILTER 15 #define CONTROL_BTNPARTYMODE 16 #define CONTROL_BTNMANUALINFO 17 #define CONTROL_BTN_FILTER 19 #define CONTROL_UPDATE_LIBRARY 20 CGUIWindowMusicNav::CGUIWindowMusicNav(void) : CGUIWindowMusicBase(WINDOW_MUSIC_NAV, "MyMusicNav.xml") { m_vecItems->SetPath("?"); m_searchWithEdit = false; } CGUIWindowMusicNav::~CGUIWindowMusicNav(void) = default; bool CGUIWindowMusicNav::OnMessage(CGUIMessage& message) { switch (message.GetMessage()) { case GUI_MSG_WINDOW_RESET: m_vecItems->SetPath("?"); break; case GUI_MSG_WINDOW_INIT: { /* We don't want to show Autosourced items (ie removable pendrives, memorycards) in Library mode */ m_rootDir.AllowNonLocalSources(false); // is this the first time the window is opened? if (m_vecItems->GetPath() == "?" && message.GetStringParam().empty()) message.SetStringParam(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_MYMUSIC_DEFAULTLIBVIEW)); if (!CGUIWindowMusicBase::OnMessage(message)) return false; if (message.GetStringParam(0) != "") { CURL url(message.GetStringParam(0)); int i = 0; for (; i < m_vecItems->Size(); i++) { CFileItemPtr pItem = m_vecItems->Get(i); // skip ".." if (pItem->IsParentFolder()) continue; if (URIUtils::PathEquals(pItem->GetPath(), message.GetStringParam(0), true, true)) { m_viewControl.SetSelectedItem(i); i = -1; if (url.GetOption("showinfo") == "true") OnItemInfo(i); break; } } } return true; } break; case GUI_MSG_CLICKED: { int iControl = message.GetSenderId(); if (iControl == CONTROL_BTNPARTYMODE) { if (g_partyModeManager.IsEnabled()) g_partyModeManager.Disable(); else { if (!g_partyModeManager.Enable()) { SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE,false); return false; } // Playlist directory is the root of the playlist window if (m_guiState) m_guiState->SetPlaylistDirectory("playlistmusic://"); return true; } UpdateButtons(); } else if (iControl == CONTROL_SEARCH) { if (m_searchWithEdit) { // search updated - reset timer m_searchTimer.StartZero(); // grab our search string CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_SEARCH); OnMessage(selected); SetProperty("search", selected.GetLabel()); return true; } std::string search(GetProperty("search").asString()); CGUIKeyboardFactory::ShowAndGetFilter(search, true); SetProperty("search", search); return true; } else if (iControl == CONTROL_UPDATE_LIBRARY) { if (!CMusicLibraryQueue::GetInstance().IsScanningLibrary()) CMusicLibraryQueue::GetInstance().ScanLibrary(""); else CMusicLibraryQueue::GetInstance().StopLibraryScanning(); return true; } } break; case GUI_MSG_PLAYBACK_STOPPED: case GUI_MSG_PLAYBACK_ENDED: case GUI_MSG_PLAYLISTPLAYER_STOPPED: case GUI_MSG_PLAYBACK_STARTED: { SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled()); } break; case GUI_MSG_NOTIFY_ALL: { if (message.GetParam1() == GUI_MSG_SEARCH_UPDATE && IsActive()) { // search updated - reset timer m_searchTimer.StartZero(); SetProperty("search", message.GetStringParam()); } } } return CGUIWindowMusicBase::OnMessage(message); } bool CGUIWindowMusicNav::OnAction(const CAction& action) { if (action.GetID() == ACTION_SCAN_ITEM) { int item = m_viewControl.GetSelectedItem(); CMusicDatabaseDirectory dir; if (item > -1 && m_vecItems->Get(item)->m_bIsFolder && (m_vecItems->Get(item)->IsAlbum()|| dir.IsArtistDir(m_vecItems->Get(item)->GetPath()))) { OnContextButton(item,CONTEXT_BUTTON_INFO); return true; } } return CGUIWindowMusicBase::OnAction(action); } bool CGUIWindowMusicNav::ManageInfoProvider(const CFileItemPtr& item) { CQueryParams params; CDirectoryNode::GetDatabaseInfo(item->GetPath(), params); // Management of Info provider only valid for specific artist or album items if (params.GetAlbumId() == -1 && params.GetArtistId() == -1) return false; // Set things up for processing artist or albums CONTENT_TYPE content = CONTENT_ALBUMS; int id = params.GetAlbumId(); if (id == -1) { content = CONTENT_ARTISTS; id = params.GetArtistId(); } ADDON::ScraperPtr scraper; // Get specific scraper and settings for current item or use default if (!m_musicdatabase.GetScraper(id, content, scraper)) { ADDON::AddonPtr defaultScraper; if (ADDON::CAddonSystemSettings::GetInstance().GetActive( ADDON::ScraperTypeFromContent(content), defaultScraper)) { scraper = std::dynamic_pointer_cast(defaultScraper); } } // Set Information provider and settings int applyto = CGUIDialogInfoProviderSettings::Show(scraper); if (applyto >= 0) { bool result = false; CVariant msgctxt; switch (applyto) { case INFOPROVIDERAPPLYOPTIONS::INFOPROVIDER_THISITEM: // Change information provider for specific item result = m_musicdatabase.SetScraper(id, content, scraper); break; case INFOPROVIDERAPPLYOPTIONS::INFOPROVIDER_ALLVIEW: // Change information provider for the filtered items shown on this node { msgctxt = 38069; if (content == CONTENT_ARTISTS) msgctxt = 38068; if (CGUIDialogYesNo::ShowAndGetInput(CVariant{ 20195 }, msgctxt)) // Change information provider, confirm for all shown { // Set scraper for all items on current view. std::string strPath = "musicdb://"; if (content == CONTENT_ARTISTS) strPath += "artists"; else strPath += "albums"; URIUtils::AddSlashAtEnd(strPath); // Items on view could be limited by navigation criteria, smart playlist rules or a filter. // Get these options, except ID, from item path CURL musicUrl(item->GetPath()); //Use CURL, as CMusicDbUrl removes "filter" option if (content == CONTENT_ARTISTS) musicUrl.RemoveOption("artistid"); else musicUrl.RemoveOption("albumid"); strPath += musicUrl.GetOptions(); result = m_musicdatabase.SetScraperAll(strPath, scraper); } } break; case INFOPROVIDERAPPLYOPTIONS::INFOPROVIDER_DEFAULT: // Change information provider for all items { msgctxt = 38071; if (content == CONTENT_ARTISTS) msgctxt = 38070; if (CGUIDialogYesNo::ShowAndGetInput(CVariant{20195}, msgctxt)) // Change information provider, confirm default and clear { // Save scraper addon default setting values scraper->SaveSettings(); // Set default scraper const std::shared_ptr settings = CServiceBroker::GetSettingsComponent()->GetSettings(); if (content == CONTENT_ARTISTS) settings->SetString(CSettings::SETTING_MUSICLIBRARY_ARTISTSSCRAPER, scraper->ID()); else settings->SetString(CSettings::SETTING_MUSICLIBRARY_ALBUMSSCRAPER, scraper->ID()); settings->Save(); // Clear all item specific settings if (content == CONTENT_ARTISTS) result = m_musicdatabase.SetScraperAll("musicdb://artists/", nullptr); else result = m_musicdatabase.SetScraperAll("musicdb://albums/", nullptr); } } default: break; } if (!result) return false; // Refresh additional information using the new settings if (applyto == INFOPROVIDERAPPLYOPTIONS::INFOPROVIDER_ALLVIEW || applyto == INFOPROVIDERAPPLYOPTIONS::INFOPROVIDER_DEFAULT) { // Change information provider, all artists or albums if (CGUIDialogYesNo::ShowAndGetInput(CVariant{20195}, CVariant{38072})) OnItemInfoAll(m_vecItems->GetPath(), true); } else { // Change information provider, selected artist or album if (CGUIDialogYesNo::ShowAndGetInput(CVariant{20195}, CVariant{38073})) { std::string itempath = StringUtils::Format("musicdb://albums/{}/", id); if (content == CONTENT_ARTISTS) itempath = StringUtils::Format("musicdb://artists/{}/", id); OnItemInfoAll(itempath, true); } } } return true; } bool CGUIWindowMusicNav::OnClick(int iItem, const std::string &player /* = "" */) { if (iItem < 0 || iItem >= m_vecItems->Size()) return false; CFileItemPtr item = m_vecItems->Get(iItem); if (StringUtils::StartsWith(item->GetPath(), "musicsearch://")) { if (m_searchWithEdit) OnSearchUpdate(); else { std::string search(GetProperty("search").asString()); CGUIKeyboardFactory::ShowAndGetFilter(search, true); SetProperty("search", search); } return true; } if (item->IsMusicDb() && !item->m_bIsFolder) m_musicdatabase.SetPropertiesForFileItem(*item); if (item->IsPlayList() && !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_playlistAsFolders) { PlayItem(iItem); return true; } return CGUIWindowMusicBase::OnClick(iItem, player); } bool CGUIWindowMusicNav::Update(const std::string &strDirectory, bool updateFilterPath /* = true */) { if (m_thumbLoader.IsLoading()) m_thumbLoader.StopThread(); if (CGUIWindowMusicBase::Update(strDirectory, updateFilterPath)) { m_thumbLoader.Load(*m_unfilteredItems); return true; } return false; } bool CGUIWindowMusicNav::GetDirectory(const std::string &strDirectory, CFileItemList &items) { if (strDirectory.empty()) AddSearchFolder(); bool bResult = CGUIWindowMusicBase::GetDirectory(strDirectory, items); if (bResult) { if (items.IsPlayList()) OnRetrieveMusicInfo(items); } // update our content in the info manager if (StringUtils::StartsWithNoCase(strDirectory, "videodb://") || items.IsVideoDb()) { CVideoDatabaseDirectory dir; VIDEODATABASEDIRECTORY::NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath()); if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_TITLE_MUSICVIDEOS || node == VIDEODATABASEDIRECTORY::NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS) items.SetContent("musicvideos"); else if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_GENRE) items.SetContent("genres"); else if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_COUNTRY) items.SetContent("countries"); else if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_ACTOR) items.SetContent("artists"); else if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_DIRECTOR) items.SetContent("directors"); else if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_STUDIO) items.SetContent("studios"); else if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_YEAR) items.SetContent("years"); else if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_MUSICVIDEOS_ALBUM) items.SetContent("albums"); else if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_TAGS) items.SetContent("tags"); else items.SetContent(""); } else if (StringUtils::StartsWithNoCase(strDirectory, "musicdb://") || items.IsMusicDb()) { CMusicDatabaseDirectory dir; NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath()); if (node == NODE_TYPE_ALBUM || node == NODE_TYPE_ALBUM_RECENTLY_ADDED || node == NODE_TYPE_ALBUM_RECENTLY_PLAYED || node == NODE_TYPE_ALBUM_TOP100 || node == NODE_TYPE_DISC) // ! @todo: own content type "discs"?? items.SetContent("albums"); else if (node == NODE_TYPE_ARTIST) items.SetContent("artists"); else if (node == NODE_TYPE_SONG || node == NODE_TYPE_SONG_TOP100 || node == NODE_TYPE_SINGLES || node == NODE_TYPE_ALBUM_RECENTLY_ADDED_SONGS || node == NODE_TYPE_ALBUM_RECENTLY_PLAYED_SONGS || node == NODE_TYPE_ALBUM_TOP100_SONGS) items.SetContent("songs"); else if (node == NODE_TYPE_GENRE) items.SetContent("genres"); else if (node == NODE_TYPE_SOURCE) items.SetContent("sources"); else if (node == NODE_TYPE_ROLE) items.SetContent("roles"); else if (node == NODE_TYPE_YEAR) items.SetContent("years"); else items.SetContent(""); } else if (items.IsPlayList()) items.SetContent("songs"); else if (URIUtils::PathEquals(strDirectory, "special://musicplaylists/") || URIUtils::PathEquals(strDirectory, "library://music/playlists.xml/")) items.SetContent("playlists"); else if (URIUtils::PathEquals(strDirectory, "plugin://music/")) items.SetContent("plugins"); else if (items.IsAddonsPath()) items.SetContent("addons"); else if (!items.IsSourcesPath() && !items.IsVirtualDirectoryRoot() && !items.IsLibraryFolder() && !items.IsPlugin() && !items.IsSmartPlayList()) items.SetContent("files"); return bResult; } void CGUIWindowMusicNav::UpdateButtons() { CGUIWindowMusicBase::UpdateButtons(); // Update object count int iItems = m_vecItems->Size(); if (iItems) { // check for parent dir and "all" items // should always be the first two items for (int i = 0; i <= (iItems>=2 ? 1 : 0); i++) { CFileItemPtr pItem = m_vecItems->Get(i); if (pItem->IsParentFolder()) iItems--; if (StringUtils::StartsWith(pItem->GetPath(), "/-1/")) iItems--; } // or the last item if (m_vecItems->Size() > 2 && StringUtils::StartsWith(m_vecItems->Get(m_vecItems->Size()-1)->GetPath(), "/-1/")) iItems--; } std::string items = StringUtils::Format("{} {}", iItems, g_localizeStrings.Get(127)); SET_CONTROL_LABEL(CONTROL_LABELFILES, items); // set the filter label std::string strLabel; // "Playlists" if (m_vecItems->IsPath("special://musicplaylists/")) strLabel = g_localizeStrings.Get(136); // "{Playlist Name}" else if (m_vecItems->IsPlayList()) { // get playlist name from path std::string strDummy; URIUtils::Split(m_vecItems->GetPath(), strDummy, strLabel); } // everything else is from a musicdb:// path else { CMusicDatabaseDirectory dir; dir.GetLabel(m_vecItems->GetPath(), strLabel); } SET_CONTROL_LABEL(CONTROL_FILTER, strLabel); SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled()); CONTROL_ENABLE_ON_CONDITION(CONTROL_UPDATE_LIBRARY, !m_vecItems->IsAddonsPath() && !m_vecItems->IsPlugin() && !m_vecItems->IsScript()); } void CGUIWindowMusicNav::PlayItem(int iItem) { // unlike additemtoplaylist, we need to check the items here // before calling it since the current playlist will be stopped // and cleared! // root is not allowed if (m_vecItems->IsVirtualDirectoryRoot() && !m_vecItems->Get(iItem)->IsDVD()) return; CGUIWindowMusicBase::PlayItem(iItem); } void CGUIWindowMusicNav::OnWindowLoaded() { const CGUIControl *control = GetControl(CONTROL_SEARCH); m_searchWithEdit = (control && control->GetControlType() == CGUIControl::GUICONTROL_EDIT); CGUIWindowMusicBase::OnWindowLoaded(); if (m_searchWithEdit) { SendMessage(GUI_MSG_SET_TYPE, CONTROL_SEARCH, CGUIEditControl::INPUT_TYPE_SEARCH); SET_CONTROL_LABEL2(CONTROL_SEARCH, GetProperty("search").asString()); } } void CGUIWindowMusicNav::GetContextButtons(int itemNumber, CContextButtons &buttons) { CFileItemPtr item; if (itemNumber >= 0 && itemNumber < m_vecItems->Size()) item = m_vecItems->Get(itemNumber); if (item) { const std::shared_ptr profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager(); // are we in the playlists location? bool inPlaylists = m_vecItems->IsPath(CUtil::MusicPlaylistsLocation()) || m_vecItems->IsPath("special://musicplaylists/"); if (m_vecItems->IsPath("sources://music/")) { // get the usual music shares, and anything for all media windows CGUIDialogContextMenu::GetContextButtons("music", item, buttons); #ifdef HAS_DVD_DRIVE // enable Rip CD an audio disc if (CServiceBroker::GetMediaManager().IsDiscInDrive() && item->IsCDDA()) { // those cds can also include Audio Tracks: CDExtra and MixedMode! MEDIA_DETECT::CCdInfo* pCdInfo = CServiceBroker::GetMediaManager().GetCdInfo(); if (pCdInfo->IsAudio(1) || pCdInfo->IsCDExtra(1) || pCdInfo->IsMixedMode(1)) { if (CServiceBroker::GetJobManager()->IsProcessing("cdrip")) buttons.Add(CONTEXT_BUTTON_CANCEL_RIP_CD, 14100); else buttons.Add(CONTEXT_BUTTON_RIP_CD, 600); } } #endif // Scan button for music sources except ".." and "Add music source" items if (!item->IsPath("add") && !item->IsParentFolder() && (profileManager->GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser)) { buttons.Add(CONTEXT_BUTTON_SCAN, 13352); } CGUIMediaWindow::GetContextButtons(itemNumber, buttons); } else { CGUIWindowMusicBase::GetContextButtons(itemNumber, buttons); // Scan button for real folders containing files when navigating within music sources. // Blacklist the bespoke Kodi protocols as to many valid external protocols to whitelist if (m_vecItems->GetContent() == "files" && // Other content not scanned to library !inPlaylists && !m_vecItems->IsInternetStream() && // Not playlists locations or streams !item->IsPath("add") && !item->IsParentFolder() && // Not ".." and "Add items item->m_bIsFolder && // Folders only, but playlists can be folders too !URIUtils::IsLibraryContent(item->GetPath()) && // database folder or .xsp files !URIUtils::IsSpecial(item->GetPath()) && !item->IsPlugin() && !item->IsScript() && !item->IsPlayList() && // .m3u etc. that as flagged as folders when playlistasfolders !StringUtils::StartsWithNoCase(item->GetPath(), "addons://") && (profileManager->GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser)) { buttons.Add(CONTEXT_BUTTON_SCAN, 13352); } CMusicDatabaseDirectory dir; if (!item->IsParentFolder() && !dir.IsAllItem(item->GetPath())) { if (item->m_bIsFolder && !item->IsVideoDb() && !item->IsPlugin() && !StringUtils::StartsWithNoCase(item->GetPath(), "musicsearch://")) { if (item->IsAlbum()) // enable query all albums button only in album view buttons.Add(CONTEXT_BUTTON_INFO_ALL, 20059); else if (dir.IsArtistDir(item->GetPath())) // enable query all artist button only in artist view buttons.Add(CONTEXT_BUTTON_INFO_ALL, 21884); //Set default or clear default NODE_TYPE nodetype = dir.GetDirectoryType(item->GetPath()); if (!inPlaylists && (nodetype == NODE_TYPE_ROOT || nodetype == NODE_TYPE_OVERVIEW || nodetype == NODE_TYPE_TOP100)) { const std::shared_ptr settings = CServiceBroker::GetSettingsComponent()->GetSettings(); if (!item->IsPath(settings->GetString(CSettings::SETTING_MYMUSIC_DEFAULTLIBVIEW))) buttons.Add(CONTEXT_BUTTON_SET_DEFAULT, 13335); // set default if (!settings->GetString(CSettings::SETTING_MYMUSIC_DEFAULTLIBVIEW).empty()) buttons.Add(CONTEXT_BUTTON_CLEAR_DEFAULT, 13403); // clear default } //Change information provider if (StringUtils::EqualsNoCase(m_vecItems->GetContent(), "albums") || StringUtils::EqualsNoCase(m_vecItems->GetContent(), "artists")) { // we allow the user to set information provider for albums and artists buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20195); } } if (item->HasMusicInfoTag() && !item->GetMusicInfoTag()->GetArtistString().empty()) { CVideoDatabase database; database.Open(); if (database.GetMatchingMusicVideo(item->GetMusicInfoTag()->GetArtistString()) > -1) buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20400); } if (item->HasMusicInfoTag() && !item->GetMusicInfoTag()->GetArtistString().empty() && !item->GetMusicInfoTag()->GetAlbum().empty() && !item->GetMusicInfoTag()->GetTitle().empty()) { CVideoDatabase database; database.Open(); if (database.GetMatchingMusicVideo(item->GetMusicInfoTag()->GetArtistString(), item->GetMusicInfoTag()->GetAlbum(), item->GetMusicInfoTag()->GetTitle()) > -1) buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20401); } if (item->HasVideoInfoTag() && !item->m_bIsFolder) { if ((profileManager->GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser) && !item->IsPlugin()) { buttons.Add(CONTEXT_BUTTON_RENAME, 16105); buttons.Add(CONTEXT_BUTTON_DELETE, 646); } } if (inPlaylists && URIUtils::GetFileName(item->GetPath()) != "PartyMode.xsp" && (item->IsPlayList() || item->IsSmartPlayList())) buttons.Add(CONTEXT_BUTTON_DELETE, 117); if (!item->IsReadOnly() && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool("filelists.allowfiledeletion")) { buttons.Add(CONTEXT_BUTTON_DELETE, 117); buttons.Add(CONTEXT_BUTTON_RENAME, 118); } } } } // noncontextual buttons CGUIWindowMusicBase::GetNonContextButtons(buttons); } bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button) { CFileItemPtr item; if (itemNumber >= 0 && itemNumber < m_vecItems->Size()) item = m_vecItems->Get(itemNumber); switch (button) { case CONTEXT_BUTTON_INFO: { if (!item->IsVideoDb()) return CGUIWindowMusicBase::OnContextButton(itemNumber,button); // music videos - artists if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/artists/")) { int idArtist = m_musicdatabase.GetArtistByName(item->GetLabel()); if (idArtist == -1) return false; std::string path = StringUtils::Format("musicdb://artists/{}/", idArtist); CArtist artist; m_musicdatabase.GetArtist(idArtist, artist, false); *item = CFileItem(artist); item->SetPath(path); CGUIWindowMusicBase::OnContextButton(itemNumber,button); Refresh(); m_viewControl.SetSelectedItem(itemNumber); return true; } // music videos - albums if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/albums/")) { int idAlbum = m_musicdatabase.GetAlbumByName(item->GetLabel()); if (idAlbum == -1) return false; std::string path = StringUtils::Format("musicdb://albums/{}/", idAlbum); CAlbum album; m_musicdatabase.GetAlbum(idAlbum, album, false); *item = CFileItem(path,album); item->SetPath(path); CGUIWindowMusicBase::OnContextButton(itemNumber,button); Refresh(); m_viewControl.SetSelectedItem(itemNumber); return true; } if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strTitle.empty()) { CGUIDialogVideoInfo::ShowFor(*item); Refresh(); } return true; } case CONTEXT_BUTTON_INFO_ALL: OnItemInfoAll(m_vecItems->GetPath()); return true; case CONTEXT_BUTTON_SET_DEFAULT: { const std::shared_ptr settings = CServiceBroker::GetSettingsComponent()->GetSettings(); settings->SetString(CSettings::SETTING_MYMUSIC_DEFAULTLIBVIEW, item->GetPath()); settings->Save(); return true; } case CONTEXT_BUTTON_CLEAR_DEFAULT: { const std::shared_ptr settings = CServiceBroker::GetSettingsComponent()->GetSettings(); settings->SetString(CSettings::SETTING_MYMUSIC_DEFAULTLIBVIEW, ""); settings->Save(); return true; } case CONTEXT_BUTTON_GO_TO_ARTIST: { std::string strPath; CVideoDatabase database; database.Open(); strPath = StringUtils::Format( "videodb://musicvideos/artists/{}/", database.GetMatchingMusicVideo(item->GetMusicInfoTag()->GetArtistString())); CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_VIDEO_NAV,strPath); return true; } case CONTEXT_BUTTON_PLAY_OTHER: { CVideoDatabase database; database.Open(); CVideoInfoTag details; database.GetMusicVideoInfo("", details, database.GetMatchingMusicVideo(item->GetMusicInfoTag()->GetArtistString(), item->GetMusicInfoTag()->GetAlbum(), item->GetMusicInfoTag()->GetTitle())); CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY, 0, 0, static_cast(new CFileItem(details))); return true; } case CONTEXT_BUTTON_RENAME: if (!item->IsVideoDb() && !item->IsReadOnly()) OnRenameItem(itemNumber); CGUIDialogVideoInfo::UpdateVideoItemTitle(item); CUtil::DeleteVideoDatabaseDirectoryCache(); Refresh(); return true; case CONTEXT_BUTTON_DELETE: if (item->IsPlayList() || item->IsSmartPlayList()) { item->m_bIsFolder = false; CGUIComponent *gui = CServiceBroker::GetGUI(); if (gui && gui->ConfirmDelete(item->GetPath())) CFileUtils::DeleteItem(item); } else if (!item->IsVideoDb()) OnDeleteItem(itemNumber); else { CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(item); CUtil::DeleteVideoDatabaseDirectoryCache(); } Refresh(); return true; case CONTEXT_BUTTON_SET_CONTENT: return ManageInfoProvider(item); default: break; } return CGUIWindowMusicBase::OnContextButton(itemNumber, button); } bool CGUIWindowMusicNav::GetSongsFromPlayList(const std::string& strPlayList, CFileItemList &items) { std::string strParentPath=m_history.GetParentPath(); if (m_guiState.get() && !m_guiState->HideParentDirItems()) { CFileItemPtr pItem(new CFileItem("..")); pItem->SetPath(strParentPath); items.Add(pItem); } items.SetPath(strPlayList); CLog::Log(LOGDEBUG, "CGUIWindowMusicNav, opening playlist [{}]", strPlayList); std::unique_ptr pPlayList (CPlayListFactory::Create(strPlayList)); if (nullptr != pPlayList) { // load it if (!pPlayList->Load(strPlayList)) { HELPERS::ShowOKDialogText(CVariant{6}, CVariant{477}); return false; //hmmm unable to load playlist? } CPlayList playlist = *pPlayList; // convert playlist items to songs for (int i = 0; i < playlist.size(); ++i) { items.Add(playlist[i]); } } return true; } void CGUIWindowMusicNav::OnSearchUpdate() { std::string search(CURL::Encode(GetProperty("search").asString())); if (!search.empty()) { std::string path = "musicsearch://" + search + "/"; m_history.ClearSearchHistory(); Update(path); } else if (m_vecItems->IsVirtualDirectoryRoot()) { Update(""); } } void CGUIWindowMusicNav::FrameMove() { static const int search_timeout = 2000; // update our searching if (m_searchTimer.IsRunning() && m_searchTimer.GetElapsedMilliseconds() > search_timeout) { m_searchTimer.Stop(); OnSearchUpdate(); } CGUIWindowMusicBase::FrameMove(); } void CGUIWindowMusicNav::AddSearchFolder() { // we use a general viewstate (and not our member) here as our // current viewstate may be specific to some other folder, and // we know we're in the root here CFileItemList items; CGUIViewState* viewState = CGUIViewState::GetViewState(GetID(), items); if (viewState) { // add our remove the musicsearch source VECSOURCES &sources = viewState->GetSources(); bool haveSearchSource = false; bool needSearchSource = !GetProperty("search").empty() || !m_searchWithEdit; // we always need it if we don't have the edit control for (IVECSOURCES it = sources.begin(); it != sources.end(); ++it) { CMediaSource& share = *it; if (share.strPath == "musicsearch://") { haveSearchSource = true; if (!needSearchSource) { // remove it sources.erase(it); break; } } } if (!haveSearchSource && needSearchSource) { // add search share CMediaSource share; share.strName=g_localizeStrings.Get(137); // Search share.strPath = "musicsearch://"; share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL; sources.push_back(share); } m_rootDir.SetSources(sources); delete viewState; } } std::string CGUIWindowMusicNav::GetStartFolder(const std::string &dir) { std::string lower(dir); StringUtils::ToLower(lower); if (lower == "genres") return "musicdb://genres/"; else if (lower == "artists") return "musicdb://artists/"; else if (lower == "albums") return "musicdb://albums/"; else if (lower == "singles") return "musicdb://singles/"; else if (lower == "songs") return "musicdb://songs/"; else if (lower == "top100") return "musicdb://top100/"; else if (lower == "top100songs") return "musicdb://top100/songs/"; else if (lower == "top100albums") return "musicdb://top100/albums/"; else if (lower == "recentlyaddedalbums") return "musicdb://recentlyaddedalbums/"; else if (lower == "recentlyplayedalbums") return "musicdb://recentlyplayedalbums/"; else if (lower == "compilations") return "musicdb://compilations/"; else if (lower == "years") return "musicdb://years/"; else if (lower == "files") return "sources://music/"; else if (lower == "boxsets") return "musicdb://boxsets/"; return CGUIWindowMusicBase::GetStartFolder(dir); }