2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "GUIWindowMusicNav.h"
12 #include "FileItemList.h"
13 #include "GUIPassword.h"
14 #include "GUIUserMessages.h"
15 #include "PartyModeManager.h"
16 #include "ServiceBroker.h"
19 #include "addons/AddonSystemSettings.h"
20 #include "dialogs/GUIDialogYesNo.h"
21 #include "filesystem/MusicDatabaseDirectory.h"
22 #include "filesystem/VideoDatabaseDirectory.h"
23 #include "guilib/GUIComponent.h"
24 #include "guilib/GUIEditControl.h"
25 #include "guilib/GUIKeyboardFactory.h"
26 #include "guilib/GUIWindowManager.h"
27 #include "guilib/LocalizeStrings.h"
28 #include "input/actions/Action.h"
29 #include "input/actions/ActionIDs.h"
30 #include "messaging/ApplicationMessenger.h"
31 #include "messaging/helpers/DialogOKHelper.h"
32 #include "music/MusicFileItemClassify.h"
33 #include "music/MusicLibraryQueue.h"
34 #include "music/dialogs/GUIDialogInfoProviderSettings.h"
35 #include "music/tags/MusicInfoTag.h"
36 #include "network/NetworkFileItemClassify.h"
37 #include "playlists/PlayList.h"
38 #include "playlists/PlayListFactory.h"
39 #include "profiles/ProfileManager.h"
40 #include "settings/AdvancedSettings.h"
41 #include "settings/Settings.h"
42 #include "settings/SettingsComponent.h"
43 #include "storage/MediaManager.h"
44 #include "utils/FileUtils.h"
45 #include "utils/LegacyPathTranslation.h"
46 #include "utils/StringUtils.h"
47 #include "utils/URIUtils.h"
48 #include "utils/Variant.h"
49 #include "utils/log.h"
50 #include "video/VideoDatabase.h"
51 #include "video/VideoFileItemClassify.h"
52 #include "video/dialogs/GUIDialogVideoInfo.h"
53 #include "video/windows/GUIWindowVideoNav.h"
54 #include "view/GUIViewState.h"
56 using namespace XFILE
;
57 using namespace MUSICDATABASEDIRECTORY
;
59 using namespace KODI::MESSAGING
;
60 using namespace KODI::VIDEO
;
62 #define CONTROL_BTNVIEWASICONS 2
63 #define CONTROL_BTNSORTBY 3
64 #define CONTROL_BTNSORTASC 4
65 #define CONTROL_BTNTYPE 5
66 #define CONTROL_LABELFILES 12
68 #define CONTROL_SEARCH 8
69 #define CONTROL_FILTER 15
70 #define CONTROL_BTNPARTYMODE 16
71 #define CONTROL_BTNMANUALINFO 17
72 #define CONTROL_BTN_FILTER 19
74 #define CONTROL_UPDATE_LIBRARY 20
76 CGUIWindowMusicNav::CGUIWindowMusicNav(void)
77 : CGUIWindowMusicBase(WINDOW_MUSIC_NAV
, "MyMusicNav.xml")
79 m_vecItems
->SetPath("?");
80 m_searchWithEdit
= false;
83 CGUIWindowMusicNav::~CGUIWindowMusicNav(void) = default;
85 bool CGUIWindowMusicNav::OnMessage(CGUIMessage
& message
)
87 switch (message
.GetMessage())
89 case GUI_MSG_WINDOW_RESET
:
90 m_vecItems
->SetPath("?");
92 case GUI_MSG_WINDOW_INIT
:
94 /* We don't want to show Autosourced items (ie removable pendrives, memorycards) in Library mode */
95 m_rootDir
.AllowNonLocalSources(false);
97 // is this the first time the window is opened?
98 if (m_vecItems
->GetPath() == "?" && message
.GetStringParam().empty())
99 message
.SetStringParam(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_MYMUSIC_DEFAULTLIBVIEW
));
101 if (!CGUIWindowMusicBase::OnMessage(message
))
104 if (message
.GetStringParam(0) != "")
106 CURL
url(message
.GetStringParam(0));
109 for (; i
< m_vecItems
->Size(); i
++)
111 CFileItemPtr pItem
= m_vecItems
->Get(i
);
114 if (pItem
->IsParentFolder())
117 if (URIUtils::PathEquals(pItem
->GetPath(), message
.GetStringParam(0), true, true))
119 m_viewControl
.SetSelectedItem(i
);
121 if (url
.GetOption("showinfo") == "true")
132 case GUI_MSG_CLICKED
:
134 int iControl
= message
.GetSenderId();
135 if (iControl
== CONTROL_BTNPARTYMODE
)
137 if (g_partyModeManager
.IsEnabled())
138 g_partyModeManager
.Disable();
141 if (!g_partyModeManager
.Enable())
143 SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE
,false);
147 // Playlist directory is the root of the playlist window
149 m_guiState
->SetPlaylistDirectory("playlistmusic://");
155 else if (iControl
== CONTROL_SEARCH
)
157 if (m_searchWithEdit
)
159 // search updated - reset timer
160 m_searchTimer
.StartZero();
161 // grab our search string
162 CGUIMessage
selected(GUI_MSG_ITEM_SELECTED
, GetID(), CONTROL_SEARCH
);
164 SetProperty("search", selected
.GetLabel());
167 std::string
search(GetProperty("search").asString());
168 CGUIKeyboardFactory::ShowAndGetFilter(search
, true);
169 SetProperty("search", search
);
172 else if (iControl
== CONTROL_UPDATE_LIBRARY
)
174 if (!CMusicLibraryQueue::GetInstance().IsScanningLibrary())
175 CMusicLibraryQueue::GetInstance().ScanLibrary("");
177 CMusicLibraryQueue::GetInstance().StopLibraryScanning();
182 case GUI_MSG_PLAYBACK_STOPPED
:
183 case GUI_MSG_PLAYBACK_ENDED
:
184 case GUI_MSG_PLAYLISTPLAYER_STOPPED
:
185 case GUI_MSG_PLAYBACK_STARTED
:
187 SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE
, g_partyModeManager
.IsEnabled());
190 case GUI_MSG_NOTIFY_ALL
:
192 if (message
.GetParam1() == GUI_MSG_SEARCH_UPDATE
&& IsActive())
194 // search updated - reset timer
195 m_searchTimer
.StartZero();
196 SetProperty("search", message
.GetStringParam());
200 return CGUIWindowMusicBase::OnMessage(message
);
203 bool CGUIWindowMusicNav::OnAction(const CAction
& action
)
205 if (action
.GetID() == ACTION_SCAN_ITEM
)
207 int item
= m_viewControl
.GetSelectedItem();
208 CMusicDatabaseDirectory dir
;
209 if (item
> -1 && m_vecItems
->Get(item
)->m_bIsFolder
210 && (m_vecItems
->Get(item
)->IsAlbum()||
211 dir
.IsArtistDir(m_vecItems
->Get(item
)->GetPath())))
213 OnContextButton(item
,CONTEXT_BUTTON_INFO
);
218 return CGUIWindowMusicBase::OnAction(action
);
221 bool CGUIWindowMusicNav::ManageInfoProvider(const CFileItemPtr
& item
)
224 CDirectoryNode::GetDatabaseInfo(item
->GetPath(), params
);
225 // Management of Info provider only valid for specific artist or album items
226 if (params
.GetAlbumId() == -1 && params
.GetArtistId() == -1)
229 // Set things up for processing artist or albums
230 CONTENT_TYPE content
= CONTENT_ALBUMS
;
231 int id
= params
.GetAlbumId();
234 content
= CONTENT_ARTISTS
;
235 id
= params
.GetArtistId();
238 ADDON::ScraperPtr scraper
;
239 // Get specific scraper and settings for current item or use default
240 if (!m_musicdatabase
.GetScraper(id
, content
, scraper
))
242 ADDON::AddonPtr defaultScraper
;
243 if (ADDON::CAddonSystemSettings::GetInstance().GetActive(
244 ADDON::ScraperTypeFromContent(content
), defaultScraper
))
246 scraper
= std::dynamic_pointer_cast
<ADDON::CScraper
>(defaultScraper
);
250 // Set Information provider and settings
251 int applyto
= CGUIDialogInfoProviderSettings::Show(scraper
);
258 case INFOPROVIDERAPPLYOPTIONS::INFOPROVIDER_THISITEM
: // Change information provider for specific item
259 result
= m_musicdatabase
.SetScraper(id
, content
, scraper
);
261 case INFOPROVIDERAPPLYOPTIONS::INFOPROVIDER_ALLVIEW
: // Change information provider for the filtered items shown on this node
264 if (content
== CONTENT_ARTISTS
)
266 if (CGUIDialogYesNo::ShowAndGetInput(CVariant
{ 20195 }, msgctxt
)) // Change information provider, confirm for all shown
268 // Set scraper for all items on current view.
269 std::string strPath
= "musicdb://";
270 if (content
== CONTENT_ARTISTS
)
271 strPath
+= "artists";
274 URIUtils::AddSlashAtEnd(strPath
);
275 // Items on view could be limited by navigation criteria, smart playlist rules or a filter.
276 // Get these options, except ID, from item path
277 CURL
musicUrl(item
->GetPath()); //Use CURL, as CMusicDbUrl removes "filter" option
278 if (content
== CONTENT_ARTISTS
)
279 musicUrl
.RemoveOption("artistid");
281 musicUrl
.RemoveOption("albumid");
282 strPath
+= musicUrl
.GetOptions();
283 result
= m_musicdatabase
.SetScraperAll(strPath
, scraper
);
287 case INFOPROVIDERAPPLYOPTIONS::INFOPROVIDER_DEFAULT
: // Change information provider for all items
290 if (content
== CONTENT_ARTISTS
)
292 if (CGUIDialogYesNo::ShowAndGetInput(CVariant
{20195}, msgctxt
)) // Change information provider, confirm default and clear
294 // Save scraper addon default setting values
295 scraper
->SaveSettings();
296 // Set default scraper
297 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
298 if (content
== CONTENT_ARTISTS
)
299 settings
->SetString(CSettings::SETTING_MUSICLIBRARY_ARTISTSSCRAPER
, scraper
->ID());
301 settings
->SetString(CSettings::SETTING_MUSICLIBRARY_ALBUMSSCRAPER
, scraper
->ID());
303 // Clear all item specific settings
304 if (content
== CONTENT_ARTISTS
)
305 result
= m_musicdatabase
.SetScraperAll("musicdb://artists/", nullptr);
307 result
= m_musicdatabase
.SetScraperAll("musicdb://albums/", nullptr);
316 // Refresh additional information using the new settings
317 if (applyto
== INFOPROVIDERAPPLYOPTIONS::INFOPROVIDER_ALLVIEW
|| applyto
== INFOPROVIDERAPPLYOPTIONS::INFOPROVIDER_DEFAULT
)
319 // Change information provider, all artists or albums
320 if (CGUIDialogYesNo::ShowAndGetInput(CVariant
{20195}, CVariant
{38072}))
321 OnItemInfoAll(m_vecItems
->GetPath(), true);
325 // Change information provider, selected artist or album
326 if (CGUIDialogYesNo::ShowAndGetInput(CVariant
{20195}, CVariant
{38073}))
328 std::string itempath
= StringUtils::Format("musicdb://albums/{}/", id
);
329 if (content
== CONTENT_ARTISTS
)
330 itempath
= StringUtils::Format("musicdb://artists/{}/", id
);
331 OnItemInfoAll(itempath
, true);
338 bool CGUIWindowMusicNav::OnClick(int iItem
, const std::string
&player
/* = "" */)
340 if (iItem
< 0 || iItem
>= m_vecItems
->Size()) return false;
342 CFileItemPtr item
= m_vecItems
->Get(iItem
);
343 if (StringUtils::StartsWith(item
->GetPath(), "musicsearch://"))
345 if (m_searchWithEdit
)
349 std::string
search(GetProperty("search").asString());
350 CGUIKeyboardFactory::ShowAndGetFilter(search
, true);
351 SetProperty("search", search
);
355 if (MUSIC::IsMusicDb(*item
) && !item
->m_bIsFolder
)
356 m_musicdatabase
.SetPropertiesForFileItem(*item
);
358 if (item
->IsPlayList() &&
359 !CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_playlistAsFolders
)
364 return CGUIWindowMusicBase::OnClick(iItem
, player
);
367 bool CGUIWindowMusicNav::Update(const std::string
&strDirectory
, bool updateFilterPath
/* = true */)
369 if (m_thumbLoader
.IsLoading())
370 m_thumbLoader
.StopThread();
372 if (CGUIWindowMusicBase::Update(strDirectory
, updateFilterPath
))
374 m_thumbLoader
.Load(*m_unfilteredItems
);
381 bool CGUIWindowMusicNav::GetDirectory(const std::string
&strDirectory
, CFileItemList
&items
)
383 if (strDirectory
.empty())
386 bool bResult
= CGUIWindowMusicBase::GetDirectory(strDirectory
, items
);
389 if (items
.IsPlayList())
390 OnRetrieveMusicInfo(items
);
393 // update our content in the info manager
394 if (StringUtils::StartsWithNoCase(strDirectory
, "videodb://") || IsVideoDb(items
))
396 CVideoDatabaseDirectory dir
;
397 VIDEODATABASEDIRECTORY::NODE_TYPE node
= dir
.GetDirectoryChildType(items
.GetPath());
400 case VIDEODATABASEDIRECTORY::NODE_TYPE_TITLE_MUSICVIDEOS
:
401 case VIDEODATABASEDIRECTORY::NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS
:
402 items
.SetContent("musicvideos");
404 case VIDEODATABASEDIRECTORY::NODE_TYPE_GENRE
:
405 items
.SetContent("genres");
407 case VIDEODATABASEDIRECTORY::NODE_TYPE_COUNTRY
:
408 items
.SetContent("countries");
410 case VIDEODATABASEDIRECTORY::NODE_TYPE_ACTOR
:
411 items
.SetContent("artists");
413 case VIDEODATABASEDIRECTORY::NODE_TYPE_DIRECTOR
:
414 items
.SetContent("directors");
416 case VIDEODATABASEDIRECTORY::NODE_TYPE_STUDIO
:
417 items
.SetContent("studios");
419 case VIDEODATABASEDIRECTORY::NODE_TYPE_YEAR
:
420 items
.SetContent("years");
422 case VIDEODATABASEDIRECTORY::NODE_TYPE_MUSICVIDEOS_ALBUM
:
423 items
.SetContent("albums");
425 case VIDEODATABASEDIRECTORY::NODE_TYPE_TAGS
:
426 items
.SetContent("tags");
429 items
.SetContent("");
433 else if (StringUtils::StartsWithNoCase(strDirectory
, "musicdb://") || MUSIC::IsMusicDb(items
))
435 CMusicDatabaseDirectory dir
;
436 NODE_TYPE node
= dir
.GetDirectoryChildType(items
.GetPath());
439 case NODE_TYPE_ALBUM
:
440 case NODE_TYPE_ALBUM_RECENTLY_ADDED
:
441 case NODE_TYPE_ALBUM_RECENTLY_PLAYED
:
442 case NODE_TYPE_ALBUM_TOP100
:
443 case NODE_TYPE_DISC
: // ! @todo: own content type "discs"??
444 items
.SetContent("albums");
446 case NODE_TYPE_ARTIST
:
447 items
.SetContent("artists");
450 case NODE_TYPE_SONG_TOP100
:
451 case NODE_TYPE_SINGLES
:
452 case NODE_TYPE_ALBUM_RECENTLY_ADDED_SONGS
:
453 case NODE_TYPE_ALBUM_RECENTLY_PLAYED_SONGS
:
454 case NODE_TYPE_ALBUM_TOP100_SONGS
:
455 items
.SetContent("songs");
457 case NODE_TYPE_GENRE
:
458 items
.SetContent("genres");
460 case NODE_TYPE_SOURCE
:
461 items
.SetContent("sources");
464 items
.SetContent("roles");
467 items
.SetContent("years");
470 items
.SetContent("");
474 else if (items
.IsPlayList())
475 items
.SetContent("songs");
476 else if (URIUtils::PathEquals(strDirectory
, "special://musicplaylists/") ||
477 URIUtils::PathEquals(strDirectory
, "library://music/playlists.xml/"))
478 items
.SetContent("playlists");
479 else if (URIUtils::PathEquals(strDirectory
, "plugin://music/"))
480 items
.SetContent("plugins");
481 else if (items
.IsAddonsPath())
482 items
.SetContent("addons");
483 else if (!items
.IsSourcesPath() && !items
.IsVirtualDirectoryRoot() &&
484 !items
.IsLibraryFolder() && !items
.IsPlugin() && !items
.IsSmartPlayList())
485 items
.SetContent("files");
490 void CGUIWindowMusicNav::UpdateButtons()
492 CGUIWindowMusicBase::UpdateButtons();
494 // Update object count
495 int iItems
= m_vecItems
->Size();
498 // check for parent dir and "all" items
499 // should always be the first two items
500 for (int i
= 0; i
<= (iItems
>=2 ? 1 : 0); i
++)
502 CFileItemPtr pItem
= m_vecItems
->Get(i
);
503 if (pItem
->IsParentFolder()) iItems
--;
504 if (StringUtils::StartsWith(pItem
->GetPath(), "/-1/")) iItems
--;
507 if (m_vecItems
->Size() > 2 &&
508 StringUtils::StartsWith(m_vecItems
->Get(m_vecItems
->Size()-1)->GetPath(), "/-1/"))
511 std::string items
= StringUtils::Format("{} {}", iItems
, g_localizeStrings
.Get(127));
512 SET_CONTROL_LABEL(CONTROL_LABELFILES
, items
);
514 // set the filter label
515 std::string strLabel
;
518 if (m_vecItems
->IsPath("special://musicplaylists/"))
519 strLabel
= g_localizeStrings
.Get(136);
521 else if (m_vecItems
->IsPlayList())
523 // get playlist name from path
524 std::string strDummy
;
525 URIUtils::Split(m_vecItems
->GetPath(), strDummy
, strLabel
);
527 // everything else is from a musicdb:// path
530 CMusicDatabaseDirectory dir
;
531 dir
.GetLabel(m_vecItems
->GetPath(), strLabel
);
534 SET_CONTROL_LABEL(CONTROL_FILTER
, strLabel
);
536 SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE
, g_partyModeManager
.IsEnabled());
538 CONTROL_ENABLE_ON_CONDITION(CONTROL_UPDATE_LIBRARY
, !m_vecItems
->IsAddonsPath() && !m_vecItems
->IsPlugin() && !m_vecItems
->IsScript());
541 void CGUIWindowMusicNav::PlayItem(int iItem
)
543 // unlike additemtoplaylist, we need to check the items here
544 // before calling it since the current playlist will be stopped
547 // root is not allowed
548 if (m_vecItems
->IsVirtualDirectoryRoot() && !m_vecItems
->Get(iItem
)->IsDVD())
551 CGUIWindowMusicBase::PlayItem(iItem
);
554 void CGUIWindowMusicNav::OnWindowLoaded()
556 const CGUIControl
*control
= GetControl(CONTROL_SEARCH
);
557 m_searchWithEdit
= (control
&& control
->GetControlType() == CGUIControl::GUICONTROL_EDIT
);
559 CGUIWindowMusicBase::OnWindowLoaded();
561 if (m_searchWithEdit
)
563 SendMessage(GUI_MSG_SET_TYPE
, CONTROL_SEARCH
, CGUIEditControl::INPUT_TYPE_SEARCH
);
564 SET_CONTROL_LABEL2(CONTROL_SEARCH
, GetProperty("search").asString());
568 void CGUIWindowMusicNav::GetContextButtons(int itemNumber
, CContextButtons
&buttons
)
571 if (itemNumber
>= 0 && itemNumber
< m_vecItems
->Size())
572 item
= m_vecItems
->Get(itemNumber
);
575 const std::shared_ptr
<CProfileManager
> profileManager
= CServiceBroker::GetSettingsComponent()->GetProfileManager();
577 // are we in the playlists location?
578 bool inPlaylists
= m_vecItems
->IsPath(CUtil::MusicPlaylistsLocation()) ||
579 m_vecItems
->IsPath("special://musicplaylists/");
581 if (m_vecItems
->IsPath("sources://music/"))
583 // get the usual music shares, and anything for all media windows
584 CGUIDialogContextMenu::GetContextButtons("music", item
, buttons
);
585 #ifdef HAS_OPTICAL_DRIVE
586 // enable Rip CD an audio disc
587 if (CServiceBroker::GetMediaManager().IsDiscInDrive() && MUSIC::IsCDDA(*item
))
589 // those cds can also include Audio Tracks: CDExtra and MixedMode!
590 MEDIA_DETECT::CCdInfo
* pCdInfo
= CServiceBroker::GetMediaManager().GetCdInfo();
591 if (pCdInfo
->IsAudio(1) || pCdInfo
->IsCDExtra(1) || pCdInfo
->IsMixedMode(1))
593 if (CServiceBroker::GetJobManager()->IsProcessing("cdrip"))
594 buttons
.Add(CONTEXT_BUTTON_CANCEL_RIP_CD
, 14100);
596 buttons
.Add(CONTEXT_BUTTON_RIP_CD
, 600);
600 // Scan button for music sources except ".." and "Add music source" items
601 if (!item
->IsPath("add") && !item
->IsParentFolder() &&
602 (profileManager
->GetCurrentProfile().canWriteDatabases() || g_passwordManager
.bMasterUser
))
604 buttons
.Add(CONTEXT_BUTTON_SCAN
, 13352);
606 CGUIMediaWindow::GetContextButtons(itemNumber
, buttons
);
610 CGUIWindowMusicBase::GetContextButtons(itemNumber
, buttons
);
612 // Scan button for real folders containing files when navigating within music sources.
613 // Blacklist the bespoke Kodi protocols as to many valid external protocols to whitelist
614 if (m_vecItems
->GetContent() == "files" && // Other content not scanned to library
616 !NETWORK::IsInternetStream(*m_vecItems
) && // Not playlists locations or streams
617 !item
->IsPath("add") && !item
->IsParentFolder() && // Not ".." and "Add items
618 item
->m_bIsFolder
&& // Folders only, but playlists can be folders too
619 !URIUtils::IsLibraryContent(item
->GetPath()) && // database folder or .xsp files
620 !URIUtils::IsSpecial(item
->GetPath()) && !item
->IsPlugin() && !item
->IsScript() &&
621 !item
->IsPlayList() && // .m3u etc. that as flagged as folders when playlistasfolders
622 !StringUtils::StartsWithNoCase(item
->GetPath(), "addons://") &&
623 (profileManager
->GetCurrentProfile().canWriteDatabases() ||
624 g_passwordManager
.bMasterUser
))
626 buttons
.Add(CONTEXT_BUTTON_SCAN
, 13352);
629 CMusicDatabaseDirectory dir
;
631 if (!item
->IsParentFolder() && !dir
.IsAllItem(item
->GetPath()))
633 if (item
->m_bIsFolder
&& !IsVideoDb(*item
) && !item
->IsPlugin() &&
634 !StringUtils::StartsWithNoCase(item
->GetPath(), "musicsearch://"))
637 // enable query all albums button only in album view
638 buttons
.Add(CONTEXT_BUTTON_INFO_ALL
, 20059);
639 else if (dir
.IsArtistDir(item
->GetPath()))
640 // enable query all artist button only in artist view
641 buttons
.Add(CONTEXT_BUTTON_INFO_ALL
, 21884);
643 //Set default or clear default
644 NODE_TYPE nodetype
= dir
.GetDirectoryType(item
->GetPath());
646 (nodetype
== NODE_TYPE_ROOT
||
647 nodetype
== NODE_TYPE_OVERVIEW
||
648 nodetype
== NODE_TYPE_TOP100
))
650 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
651 if (!item
->IsPath(settings
->GetString(CSettings::SETTING_MYMUSIC_DEFAULTLIBVIEW
)))
652 buttons
.Add(CONTEXT_BUTTON_SET_DEFAULT
, 13335); // set default
653 if (!settings
->GetString(CSettings::SETTING_MYMUSIC_DEFAULTLIBVIEW
).empty())
654 buttons
.Add(CONTEXT_BUTTON_CLEAR_DEFAULT
, 13403); // clear default
657 //Change information provider
658 if (StringUtils::EqualsNoCase(m_vecItems
->GetContent(), "albums") ||
659 StringUtils::EqualsNoCase(m_vecItems
->GetContent(), "artists"))
661 // we allow the user to set information provider for albums and artists
662 buttons
.Add(CONTEXT_BUTTON_SET_CONTENT
, 20195);
665 if (item
->HasMusicInfoTag() && !item
->GetMusicInfoTag()->GetArtistString().empty())
667 CVideoDatabase database
;
669 if (database
.GetMatchingMusicVideo(item
->GetMusicInfoTag()->GetArtistString()) > -1)
670 buttons
.Add(CONTEXT_BUTTON_GO_TO_ARTIST
, 20400);
672 if (item
->HasMusicInfoTag() && !item
->GetMusicInfoTag()->GetArtistString().empty() &&
673 !item
->GetMusicInfoTag()->GetAlbum().empty() &&
674 !item
->GetMusicInfoTag()->GetTitle().empty())
676 CVideoDatabase database
;
678 if (database
.GetMatchingMusicVideo(item
->GetMusicInfoTag()->GetArtistString(), item
->GetMusicInfoTag()->GetAlbum(), item
->GetMusicInfoTag()->GetTitle()) > -1)
679 buttons
.Add(CONTEXT_BUTTON_PLAY_OTHER
, 20401);
681 if (item
->HasVideoInfoTag() && !item
->m_bIsFolder
)
683 if ((profileManager
->GetCurrentProfile().canWriteDatabases() || g_passwordManager
.bMasterUser
) && !item
->IsPlugin())
685 buttons
.Add(CONTEXT_BUTTON_RENAME
, 16105);
686 buttons
.Add(CONTEXT_BUTTON_DELETE
, 646);
689 if (inPlaylists
&& URIUtils::GetFileName(item
->GetPath()) != "PartyMode.xsp"
690 && (item
->IsPlayList() || item
->IsSmartPlayList()))
691 buttons
.Add(CONTEXT_BUTTON_DELETE
, 117);
693 if (!item
->IsReadOnly() && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool("filelists.allowfiledeletion"))
695 buttons
.Add(CONTEXT_BUTTON_DELETE
, 117);
696 buttons
.Add(CONTEXT_BUTTON_RENAME
, 118);
701 // noncontextual buttons
703 CGUIWindowMusicBase::GetNonContextButtons(buttons
);
706 bool CGUIWindowMusicNav::OnPopupMenu(int iItem
)
708 if (iItem
>= 0 && iItem
< m_vecItems
->Size())
710 const auto item
= m_vecItems
->Get(iItem
);
711 item
->SetProperty("CheckAutoPlayNextItem", true);
714 return CGUIWindowMusicBase::OnPopupMenu(iItem
);
717 bool CGUIWindowMusicNav::OnContextButton(int itemNumber
, CONTEXT_BUTTON button
)
720 if (itemNumber
>= 0 && itemNumber
< m_vecItems
->Size())
721 item
= m_vecItems
->Get(itemNumber
);
725 case CONTEXT_BUTTON_INFO
:
727 if (!IsVideoDb(*item
))
728 return CGUIWindowMusicBase::OnContextButton(itemNumber
,button
);
730 // music videos - artists
731 if (StringUtils::StartsWithNoCase(item
->GetPath(), "videodb://musicvideos/artists/"))
733 int idArtist
= m_musicdatabase
.GetArtistByName(item
->GetLabel());
736 std::string path
= StringUtils::Format("musicdb://artists/{}/", idArtist
);
738 m_musicdatabase
.GetArtist(idArtist
, artist
, false);
739 *item
= CFileItem(artist
);
741 CGUIWindowMusicBase::OnContextButton(itemNumber
,button
);
743 m_viewControl
.SetSelectedItem(itemNumber
);
747 // music videos - albums
748 if (StringUtils::StartsWithNoCase(item
->GetPath(), "videodb://musicvideos/albums/"))
750 int idAlbum
= m_musicdatabase
.GetAlbumByName(item
->GetLabel());
753 std::string path
= StringUtils::Format("musicdb://albums/{}/", idAlbum
);
755 m_musicdatabase
.GetAlbum(idAlbum
, album
, false);
756 *item
= CFileItem(path
,album
);
758 CGUIWindowMusicBase::OnContextButton(itemNumber
,button
);
760 m_viewControl
.SetSelectedItem(itemNumber
);
764 if (item
->HasVideoInfoTag() && !item
->GetVideoInfoTag()->m_strTitle
.empty())
766 CGUIDialogVideoInfo::ShowFor(*item
);
772 case CONTEXT_BUTTON_INFO_ALL
:
773 OnItemInfoAll(m_vecItems
->GetPath());
776 case CONTEXT_BUTTON_SET_DEFAULT
:
778 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
779 settings
->SetString(CSettings::SETTING_MYMUSIC_DEFAULTLIBVIEW
, item
->GetPath());
784 case CONTEXT_BUTTON_CLEAR_DEFAULT
:
786 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
787 settings
->SetString(CSettings::SETTING_MYMUSIC_DEFAULTLIBVIEW
, "");
792 case CONTEXT_BUTTON_GO_TO_ARTIST
:
795 CVideoDatabase database
;
797 strPath
= StringUtils::Format(
798 "videodb://musicvideos/artists/{}/",
799 database
.GetMatchingMusicVideo(item
->GetMusicInfoTag()->GetArtistString()));
800 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_VIDEO_NAV
,strPath
);
804 case CONTEXT_BUTTON_PLAY_OTHER
:
806 CVideoDatabase database
;
808 CVideoInfoTag details
;
809 database
.GetMusicVideoInfo("", details
, database
.GetMatchingMusicVideo(item
->GetMusicInfoTag()->GetArtistString(), item
->GetMusicInfoTag()->GetAlbum(), item
->GetMusicInfoTag()->GetTitle()));
810 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY
, 0, 0,
811 static_cast<void*>(new CFileItem(details
)));
815 case CONTEXT_BUTTON_RENAME
:
816 if (!IsVideoDb(*item
) && !item
->IsReadOnly())
817 OnRenameItem(itemNumber
);
819 CGUIDialogVideoInfo::UpdateVideoItemTitle(item
);
820 CUtil::DeleteVideoDatabaseDirectoryCache();
824 case CONTEXT_BUTTON_DELETE
:
825 if (item
->IsPlayList() || item
->IsSmartPlayList())
827 item
->m_bIsFolder
= false;
828 CGUIComponent
*gui
= CServiceBroker::GetGUI();
829 if (gui
&& gui
->ConfirmDelete(item
->GetPath()))
830 CFileUtils::DeleteItem(item
);
832 else if (!IsVideoDb(*item
))
833 OnDeleteItem(itemNumber
);
836 CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(item
);
837 CUtil::DeleteVideoDatabaseDirectoryCache();
842 case CONTEXT_BUTTON_SET_CONTENT
:
843 return ManageInfoProvider(item
);
849 return CGUIWindowMusicBase::OnContextButton(itemNumber
, button
);
852 bool CGUIWindowMusicNav::GetSongsFromPlayList(const std::string
& strPlayList
, CFileItemList
&items
)
854 std::string strParentPath
=m_history
.GetParentPath();
856 if (m_guiState
.get() && !m_guiState
->HideParentDirItems())
858 CFileItemPtr
pItem(new CFileItem(".."));
859 pItem
->SetPath(strParentPath
);
863 items
.SetPath(strPlayList
);
864 CLog::Log(LOGDEBUG
, "CGUIWindowMusicNav, opening playlist [{}]", strPlayList
);
866 std::unique_ptr
<PLAYLIST::CPlayList
> pPlayList(PLAYLIST::CPlayListFactory::Create(strPlayList
));
867 if (nullptr != pPlayList
)
870 if (!pPlayList
->Load(strPlayList
))
872 HELPERS::ShowOKDialogText(CVariant
{6}, CVariant
{477});
873 return false; //hmmm unable to load playlist?
875 PLAYLIST::CPlayList playlist
= *pPlayList
;
876 // convert playlist items to songs
877 for (int i
= 0; i
< playlist
.size(); ++i
)
879 items
.Add(playlist
[i
]);
886 void CGUIWindowMusicNav::OnSearchUpdate()
888 std::string
search(CURL::Encode(GetProperty("search").asString()));
891 std::string path
= "musicsearch://" + search
+ "/";
892 m_history
.ClearSearchHistory();
895 else if (m_vecItems
->IsVirtualDirectoryRoot())
901 void CGUIWindowMusicNav::FrameMove()
903 static const int search_timeout
= 2000;
904 // update our searching
905 if (m_searchTimer
.IsRunning() && m_searchTimer
.GetElapsedMilliseconds() > search_timeout
)
907 m_searchTimer
.Stop();
910 CGUIWindowMusicBase::FrameMove();
913 void CGUIWindowMusicNav::AddSearchFolder()
915 // we use a general viewstate (and not our member) here as our
916 // current viewstate may be specific to some other folder, and
917 // we know we're in the root here
919 CGUIViewState
* viewState
= CGUIViewState::GetViewState(GetID(), items
);
922 // add our remove the musicsearch source
923 VECSOURCES
&sources
= viewState
->GetSources();
924 bool haveSearchSource
= false;
925 bool needSearchSource
= !GetProperty("search").empty() || !m_searchWithEdit
; // we always need it if we don't have the edit control
926 for (IVECSOURCES it
= sources
.begin(); it
!= sources
.end(); ++it
)
928 CMediaSource
& share
= *it
;
929 if (share
.strPath
== "musicsearch://")
931 haveSearchSource
= true;
932 if (!needSearchSource
)
939 if (!haveSearchSource
&& needSearchSource
)
943 share
.strName
=g_localizeStrings
.Get(137); // Search
944 share
.strPath
= "musicsearch://";
945 share
.m_iDriveType
= CMediaSource::SOURCE_TYPE_LOCAL
;
946 sources
.push_back(share
);
948 m_rootDir
.SetSources(sources
);
953 std::string
CGUIWindowMusicNav::GetStartFolder(const std::string
&dir
)
955 static const auto map
= std::map
<std::string
, std::string
>{
956 {"albums", "musicdb://albums/"},
957 {"artists", "musicdb://artists/"},
958 {"boxsets", "musicdb://boxsets/"},
959 {"compilations", "musicdb://compilations/"},
960 {"files", "sources://music/"},
961 {"genres", "musicdb://genres/"},
962 {"recentlyaddedalbums", "musicdb://recentlyaddedalbums/"},
963 {"recentlyplayedalbums", "musicdb://recentlyplayedalbums/"},
964 {"singles", "musicdb://singles/"},
965 {"songs", "musicdb://songs/"},
966 {"top100", "musicdb://top100/"},
967 {"top100albums", "musicdb://top100/albums/"},
968 {"top100songs", "musicdb://top100/songs/"},
969 {"years", "musicdb://years/"},
972 const auto it
= map
.find(StringUtils::ToLower(dir
));
974 return CGUIWindowMusicBase::GetStartFolder(dir
);