[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / video / ContextMenus.cpp
blob0d463b81050d70005ce3c76b884b3be4dbd0c4e6
1 /*
2 * Copyright (C) 2016-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.
7 */
9 #include "ContextMenus.h"
11 #include "Autorun.h"
12 #include "ContextMenuManager.h"
13 #include "FileItem.h"
14 #include "GUIUserMessages.h"
15 #include "ServiceBroker.h"
16 #include "application/Application.h"
17 #include "cores/playercorefactory/PlayerCoreFactory.h"
18 #include "guilib/GUIComponent.h"
19 #include "guilib/GUIWindowManager.h"
20 #include "guilib/LocalizeStrings.h"
21 #include "music/MusicFileItemClassify.h"
22 #include "settings/Settings.h"
23 #include "settings/SettingsComponent.h"
24 #include "utils/ContentUtils.h"
25 #include "utils/ExecString.h"
26 #include "utils/StringUtils.h"
27 #include "utils/URIUtils.h"
28 #include "video/VideoFileItemClassify.h"
29 #include "video/VideoInfoTag.h"
30 #include "video/VideoManagerTypes.h"
31 #include "video/VideoUtils.h"
32 #include "video/dialogs/GUIDialogVideoInfo.h"
33 #include "video/guilib/VideoGUIUtils.h"
34 #include "video/guilib/VideoPlayActionProcessor.h"
35 #include "video/guilib/VideoSelectActionProcessor.h"
36 #include "video/guilib/VideoVersionHelper.h"
38 #include <utility>
40 using namespace KODI;
42 namespace CONTEXTMENU
45 CVideoInfo::CVideoInfo(MediaType mediaType)
46 : CStaticContextMenuAction(19033), m_mediaType(std::move(mediaType))
50 bool CVideoInfo::IsVisible(const CFileItem& item) const
52 if (!item.HasVideoInfoTag())
53 return false;
55 if (item.IsPVRRecording())
56 return false; // pvr recordings have its own implementation for this
58 return item.GetVideoInfoTag()->m_type == m_mediaType;
61 bool CVideoInfo::Execute(const std::shared_ptr<CFileItem>& item) const
63 CGUIDialogVideoInfo::ShowFor(*item);
64 return true;
67 bool CVideoRemoveResumePoint::IsVisible(const CFileItem& itemIn) const
69 CFileItem item(itemIn.GetItemToPlay());
70 if (item.IsDeleted()) // e.g. trashed pvr recording
71 return false;
73 // Folders don't have a resume point
74 return !item.m_bIsFolder && VIDEO::UTILS::GetItemResumeInformation(item).isResumable;
77 bool CVideoRemoveResumePoint::Execute(const std::shared_ptr<CFileItem>& item) const
79 CVideoLibraryQueue::GetInstance().ResetResumePoint(item);
80 return true;
83 bool CVideoMarkWatched::IsVisible(const CFileItem& item) const
85 if (item.IsDeleted()) // e.g. trashed pvr recording
86 return false;
88 if (item.m_bIsFolder && item.IsPlugin()) // we cannot manage plugin folder's watched state
89 return false;
91 if (item.m_bIsFolder) // Only allow video db content, video and recording folders to be updated recursively
93 if (item.HasVideoInfoTag())
94 return VIDEO::IsVideoDb(item);
95 else if (item.GetProperty("IsVideoFolder").asBoolean())
96 return true;
97 else
98 return !item.IsParentFolder() && URIUtils::IsPVRRecordingFileOrFolder(item.GetPath());
100 else if (!item.HasVideoInfoTag())
101 return false;
103 return item.GetVideoInfoTag()->GetPlayCount() == 0;
106 bool CVideoMarkWatched::Execute(const std::shared_ptr<CFileItem>& item) const
108 CVideoLibraryQueue::GetInstance().MarkAsWatched(item, true);
109 return true;
112 bool CVideoMarkUnWatched::IsVisible(const CFileItem& item) const
114 if (item.IsDeleted()) // e.g. trashed pvr recording
115 return false;
117 if (item.m_bIsFolder && item.IsPlugin()) // we cannot manage plugin folder's watched state
118 return false;
120 if (item.m_bIsFolder) // Only allow video db content, video and recording folders to be updated recursively
122 if (item.HasVideoInfoTag())
123 return VIDEO::IsVideoDb(item);
124 else if (item.GetProperty("IsVideoFolder").asBoolean())
125 return true;
126 else
127 return !item.IsParentFolder() && URIUtils::IsPVRRecordingFileOrFolder(item.GetPath());
129 else if (!item.HasVideoInfoTag())
130 return false;
132 return item.GetVideoInfoTag()->GetPlayCount() > 0;
135 bool CVideoMarkUnWatched::Execute(const std::shared_ptr<CFileItem>& item) const
137 CVideoLibraryQueue::GetInstance().MarkAsWatched(item, false);
138 return true;
141 bool CVideoBrowse::IsVisible(const CFileItem& item) const
143 return ((item.m_bIsFolder || item.IsFileFolder(EFILEFOLDER_MASK_ONBROWSE)) &&
144 VIDEO::UTILS::IsItemPlayable(item));
147 bool CVideoBrowse::Execute(const std::shared_ptr<CFileItem>& item) const
149 int target = WINDOW_INVALID;
150 if (URIUtils::IsPVRRadioRecordingFileOrFolder(item->GetPath()))
151 target = WINDOW_RADIO_RECORDINGS;
152 else if (URIUtils::IsPVRTVRecordingFileOrFolder(item->GetPath()))
153 target = WINDOW_TV_RECORDINGS;
154 else
155 target = WINDOW_VIDEO_NAV;
157 auto& windowMgr = CServiceBroker::GetGUI()->GetWindowManager();
159 // For file directory browsing, we need item's dyn path, for everything else the path.
160 const std::string path{item->IsFileFolder(EFILEFOLDER_MASK_ONBROWSE) ? item->GetDynPath()
161 : item->GetPath()};
163 if (target == windowMgr.GetActiveWindow())
165 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, target, 0, GUI_MSG_UPDATE);
166 msg.SetStringParam(path);
167 windowMgr.SendMessage(msg);
169 else
171 windowMgr.ActivateWindow(target, {path, "return"});
173 return true;
176 namespace
178 bool ExecuteAction(const CExecString& execute)
180 const std::string& execStr{execute.GetExecString()};
181 if (!execStr.empty())
183 CGUIMessage message(GUI_MSG_EXECUTE, 0, 0);
184 message.SetStringParam(execStr);
185 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(message);
186 return true;
188 return false;
191 class CVideoSelectActionProcessor : public VIDEO::GUILIB::CVideoSelectActionProcessorBase
193 public:
194 explicit CVideoSelectActionProcessor(const std::shared_ptr<CFileItem>& item)
195 : CVideoSelectActionProcessorBase(item)
199 protected:
200 bool OnPlayPartSelected(unsigned int part) override
202 // part numbers are 1-based
203 ExecuteAction({"PlayMedia", *m_item, StringUtils::Format("playoffset={}", part - 1)});
204 return true;
207 bool OnResumeSelected() override
209 ExecuteAction({"PlayMedia", *m_item, "resume"});
210 return true;
213 bool OnPlaySelected() override
215 ExecuteAction({"PlayMedia", *m_item, "noresume"});
216 return true;
219 bool OnQueueSelected() override
221 ExecuteAction({"QueueMedia", *m_item, ""});
222 return true;
225 bool OnInfoSelected() override
227 CGUIDialogVideoInfo::ShowFor(*m_item);
228 return true;
231 bool OnMoreSelected() override
233 CONTEXTMENU::ShowFor(m_item, CContextMenuManager::MAIN);
234 return true;
237 } // unnamed namespace
239 bool CVideoChooseVersion::IsVisible(const CFileItem& item) const
241 return item.HasVideoVersions() &&
242 !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
243 CSettings::SETTING_VIDEOLIBRARY_SHOWVIDEOVERSIONSASFOLDER) &&
244 !VIDEO::IsVideoAssetFile(item);
247 bool CVideoChooseVersion::Execute(const std::shared_ptr<CFileItem>& item) const
249 // force selection dialog, regardless of any settings like 'Select default video version'
250 item->SetProperty("needs_resolved_video_asset", true);
251 item->SetProperty("video_asset_type", static_cast<int>(VideoAssetType::VERSION));
252 CVideoSelectActionProcessor proc{item};
253 const bool ret = proc.ProcessDefaultAction();
254 item->ClearProperty("needs_resolved_video_asset");
255 item->ClearProperty("video_asset_type");
256 return ret;
259 std::string CVideoResume::GetLabel(const CFileItem& item) const
261 return VIDEO::UTILS::GetResumeString(item.GetItemToPlay());
264 bool CVideoResume::IsVisible(const CFileItem& itemIn) const
266 CFileItem item(itemIn.GetItemToPlay());
267 if (item.IsDeleted()) // e.g. trashed pvr recording
268 return false;
270 return VIDEO::UTILS::GetItemResumeInformation(item).isResumable;
273 namespace
275 std::vector<std::string> GetPlayers(const CPlayerCoreFactory& playerCoreFactory,
276 const CFileItem& item)
278 std::vector<std::string> players;
279 if (VIDEO::IsVideoDb(item))
281 //! @todo CPlayerCoreFactory and classes called from there do not handle dyn path correctly.
282 CFileItem item2{item};
283 item2.SetPath(item.GetDynPath());
284 playerCoreFactory.GetPlayers(item2, players);
286 else
287 playerCoreFactory.GetPlayers(item, players);
289 return players;
292 class CVideoPlayActionProcessor : public VIDEO::GUILIB::CVideoPlayActionProcessorBase
294 public:
295 CVideoPlayActionProcessor(const std::shared_ptr<CFileItem>& item, bool choosePlayer)
296 : CVideoPlayActionProcessorBase(item), m_choosePlayer(choosePlayer)
300 protected:
301 bool OnResumeSelected() override
303 m_item->SetStartOffset(STARTOFFSET_RESUME);
304 Play();
305 return true;
308 bool OnPlaySelected() override
310 std::string player;
311 if (m_choosePlayer)
313 const CPlayerCoreFactory& playerCoreFactory{CServiceBroker::GetPlayerCoreFactory()};
314 const std::vector<std::string> players{GetPlayers(playerCoreFactory, *m_item)};
315 player = playerCoreFactory.SelectPlayerDialog(players);
316 if (player.empty())
318 m_userCancelled = true;
319 return true; // User cancelled player selection. We're done.
323 Play(player);
324 return true;
327 private:
328 void Play(const std::string& player = "")
330 m_item->SetProperty("playlist_type_hint", static_cast<int>(PLAYLIST::Id::TYPE_VIDEO));
331 const ContentUtils::PlayMode mode{m_item->GetProperty("CheckAutoPlayNextItem").asBoolean()
332 ? ContentUtils::PlayMode::CHECK_AUTO_PLAY_NEXT_ITEM
333 : ContentUtils::PlayMode::PLAY_ONLY_THIS};
334 VIDEO::UTILS::PlayItem(m_item, player, mode);
337 const bool m_choosePlayer{false};
340 enum class PlayMode
342 PLAY,
343 PLAY_USING,
344 PLAY_VERSION_USING,
345 RESUME,
347 void SetPathAndPlay(const std::shared_ptr<CFileItem>& item, PlayMode mode)
349 item->SetProperty("check_resume", false);
351 if (item->IsLiveTV()) // pvr tv or pvr radio?
353 g_application.PlayMedia(*item, "", PLAYLIST::Id::TYPE_VIDEO);
355 else
357 const auto itemCopy{std::make_shared<CFileItem>(*item)};
358 if (VIDEO::IsVideoDb(*itemCopy))
360 if (!itemCopy->m_bIsFolder)
362 itemCopy->SetProperty("original_listitem_url", item->GetPath());
363 itemCopy->SetPath(item->GetVideoInfoTag()->m_strFileNameAndPath);
365 else if (itemCopy->HasVideoInfoTag() && itemCopy->GetVideoInfoTag()->IsDefaultVideoVersion())
367 //! @todo get rid of "videos with versions as folder" hack!
368 itemCopy->m_bIsFolder = false;
372 if (mode == PlayMode::PLAY_VERSION_USING)
374 // force video version selection dialog
375 itemCopy->SetProperty("needs_resolved_video_asset", true);
377 else
379 // play the given/default video version, if multiple versions are available
380 itemCopy->SetProperty("has_resolved_video_asset", true);
383 const bool choosePlayer{mode == PlayMode::PLAY_USING || mode == PlayMode::PLAY_VERSION_USING};
384 CVideoPlayActionProcessor proc{itemCopy, choosePlayer};
385 if (mode == PlayMode::RESUME && (itemCopy->GetStartOffset() == STARTOFFSET_RESUME ||
386 VIDEO::UTILS::GetItemResumeInformation(*item).isResumable))
387 proc.ProcessAction(VIDEO::GUILIB::ACTION_RESUME);
388 else // all other modes are actually PLAY
389 proc.ProcessAction(VIDEO::GUILIB::ACTION_PLAY_FROM_BEGINNING);
392 } // unnamed namespace
394 bool CVideoResume::Execute(const std::shared_ptr<CFileItem>& itemIn) const
396 const auto item{std::make_shared<CFileItem>(itemIn->GetItemToPlay())};
397 #ifdef HAS_OPTICAL_DRIVE
398 if (item->IsDVD() || MUSIC::IsCDDA(*item))
399 return MEDIA_DETECT::CAutorun::PlayDisc(item->GetPath(), true, false);
400 #endif
402 item->SetStartOffset(STARTOFFSET_RESUME);
403 SetPathAndPlay(item, PlayMode::RESUME);
404 return true;
407 std::string CVideoPlay::GetLabel(const CFileItem& itemIn) const
409 CFileItem item(itemIn.GetItemToPlay());
410 if (item.IsLiveTV())
411 return g_localizeStrings.Get(19000); // Switch to channel
412 if (VIDEO::UTILS::GetItemResumeInformation(item).isResumable)
413 return g_localizeStrings.Get(12021); // Play from beginning
414 return g_localizeStrings.Get(208); // Play
417 bool CVideoPlay::IsVisible(const CFileItem& item) const
419 return VIDEO::UTILS::IsItemPlayable(item);
422 bool CVideoPlay::Execute(const std::shared_ptr<CFileItem>& itemIn) const
424 const auto item{std::make_shared<CFileItem>(itemIn->GetItemToPlay())};
425 #ifdef HAS_OPTICAL_DRIVE
426 if (item->IsDVD() || MUSIC::IsCDDA(*item))
427 return MEDIA_DETECT::CAutorun::PlayDisc(item->GetPath(), true, true);
428 #endif
429 SetPathAndPlay(item, PlayMode::PLAY);
430 return true;
433 bool CVideoPlayUsing::IsVisible(const CFileItem& item) const
435 if (item.HasVideoVersions() &&
436 !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
437 CSettings::SETTING_VIDEOLIBRARY_SHOWVIDEOVERSIONSASFOLDER) &&
438 !VIDEO::IsVideoAssetFile(item))
439 return false;
441 if (item.IsLiveTV())
442 return false;
444 const CPlayerCoreFactory& playerCoreFactory{CServiceBroker::GetPlayerCoreFactory()};
445 return (GetPlayers(playerCoreFactory, item).size() > 1) && VIDEO::UTILS::IsItemPlayable(item);
448 bool CVideoPlayUsing::Execute(const std::shared_ptr<CFileItem>& itemIn) const
450 const auto item{std::make_shared<CFileItem>(itemIn->GetItemToPlay())};
451 SetPathAndPlay(item, PlayMode::PLAY_USING);
452 return true;
455 bool CVideoPlayVersionUsing::IsVisible(const CFileItem& item) const
457 return item.HasVideoVersions() &&
458 !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
459 CSettings::SETTING_VIDEOLIBRARY_SHOWVIDEOVERSIONSASFOLDER) &&
460 !VIDEO::IsVideoAssetFile(item);
463 bool CVideoPlayVersionUsing::Execute(const std::shared_ptr<CFileItem>& itemIn) const
465 const auto item{std::make_shared<CFileItem>(itemIn->GetItemToPlay())};
466 item->SetProperty("video_asset_type", static_cast<int>(VideoAssetType::VERSION));
467 SetPathAndPlay(item, PlayMode::PLAY_VERSION_USING);
468 return true;
471 namespace
473 void SelectNextItem(int windowID)
475 auto& windowMgr = CServiceBroker::GetGUI()->GetWindowManager();
476 CGUIWindow* window = windowMgr.GetWindow(windowID);
477 if (window)
479 const int viewContainerID = window->GetViewContainerID();
480 if (viewContainerID > 0)
482 CGUIMessage msg1(GUI_MSG_ITEM_SELECTED, windowID, viewContainerID);
483 windowMgr.SendMessage(msg1, windowID);
485 CGUIMessage msg2(GUI_MSG_ITEM_SELECT, windowID, viewContainerID, msg1.GetParam1() + 1);
486 windowMgr.SendMessage(msg2, windowID);
491 bool CanQueue(const CFileItem& item)
493 if (!item.CanQueue())
494 return false;
496 const int windowId = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
497 if (windowId == WINDOW_VIDEO_PLAYLIST)
498 return false; // Already queued
500 return true;
502 } // unnamed namespace
504 bool CVideoQueue::IsVisible(const CFileItem& item) const
506 if (!CanQueue(item))
507 return false;
509 return VIDEO::UTILS::IsItemPlayable(item);
512 bool CVideoQueue::Execute(const std::shared_ptr<CFileItem>& item) const
514 VIDEO::UTILS::QueueItem(item, VIDEO::UTILS::QueuePosition::POSITION_END);
516 // Set selection to next item in active window's view.
517 const int windowID = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
518 SelectNextItem(windowID);
520 return true;
523 bool CVideoPlayNext::IsVisible(const CFileItem& item) const
525 if (!CanQueue(item))
526 return false;
528 return VIDEO::UTILS::IsItemPlayable(item);
531 bool CVideoPlayNext::Execute(const std::shared_ptr<CFileItem>& item) const
533 VIDEO::UTILS::QueueItem(item, VIDEO::UTILS::QueuePosition::POSITION_BEGIN);
534 return true;
537 std::string CVideoPlayAndQueue::GetLabel(const CFileItem& item) const
539 if (VIDEO::UTILS::IsAutoPlayNextItem(item))
540 return g_localizeStrings.Get(13434); // Play only this
541 else
542 return g_localizeStrings.Get(13412); // Play from here
545 bool CVideoPlayAndQueue::IsVisible(const CFileItem& item) const
547 if (!CanQueue(item))
548 return false;
550 const int windowId = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
551 if ((windowId == WINDOW_TV_RECORDINGS || windowId == WINDOW_RADIO_RECORDINGS) &&
552 item.IsUsablePVRRecording())
553 return true;
555 return false; //! @todo implement
558 bool CVideoPlayAndQueue::Execute(const std::shared_ptr<CFileItem>& item) const
560 const int windowId = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
561 if ((windowId == WINDOW_TV_RECORDINGS || windowId == WINDOW_RADIO_RECORDINGS) &&
562 item->IsUsablePVRRecording())
564 const ContentUtils::PlayMode mode = VIDEO::UTILS::IsAutoPlayNextItem(*item)
565 ? ContentUtils::PlayMode::PLAY_ONLY_THIS
566 : ContentUtils::PlayMode::PLAY_FROM_HERE;
567 VIDEO::UTILS::PlayItem(item, "", mode);
568 return true;
571 return true; //! @todo implement