[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / video / dialogs / GUIDialogVideoManager.cpp
blob6b83e44a4b0784613ace163a89c46cce55630281
1 /*
2 * Copyright (C) 2023 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 "GUIDialogVideoManager.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "GUIUserMessages.h"
14 #include "MediaSource.h"
15 #include "ServiceBroker.h"
16 #include "dialogs/GUIDialogOK.h"
17 #include "dialogs/GUIDialogSelect.h"
18 #include "dialogs/GUIDialogYesNo.h"
19 #include "filesystem/Directory.h"
20 #include "guilib/GUIComponent.h"
21 #include "guilib/GUIKeyboardFactory.h"
22 #include "guilib/GUIWindowManager.h"
23 #include "guilib/LocalizeStrings.h"
24 #include "input/actions/Action.h"
25 #include "input/actions/ActionIDs.h"
26 #include "playlists/PlayListTypes.h"
27 #include "utils/ContentUtils.h"
28 #include "utils/StringUtils.h"
29 #include "utils/URIUtils.h"
30 #include "utils/log.h"
31 #include "video/VideoManagerTypes.h"
32 #include "video/VideoThumbLoader.h"
33 #include "video/dialogs/GUIDialogVideoInfo.h"
34 #include "video/guilib/VideoGUIUtils.h"
35 #include "video/guilib/VideoPlayActionProcessor.h"
37 #include <algorithm>
38 #include <string>
40 using namespace KODI;
42 static constexpr unsigned int CONTROL_LABEL_TITLE = 2;
44 static constexpr unsigned int CONTROL_BUTTON_PLAY = 21;
45 static constexpr unsigned int CONTROL_BUTTON_REMOVE = 26;
46 static constexpr unsigned int CONTROL_BUTTON_CHOOSE_ART = 27;
48 static constexpr unsigned int CONTROL_LIST_ASSETS = 50;
50 CGUIDialogVideoManager::CGUIDialogVideoManager(int windowId)
51 : CGUIDialog(windowId, "DialogVideoManager.xml"),
52 m_videoAsset(std::make_shared<CFileItem>()),
53 m_videoAssetsList(std::make_unique<CFileItemList>()),
54 m_selectedVideoAsset(std::make_shared<CFileItem>())
56 m_loadType = KEEP_IN_MEMORY;
59 bool CGUIDialogVideoManager::OnMessage(CGUIMessage& message)
61 switch (message.GetMessage())
63 case GUI_MSG_WINDOW_DEINIT:
65 Clear();
66 break;
69 case GUI_MSG_CLICKED:
71 const int control{message.GetSenderId()};
72 if (control == CONTROL_LIST_ASSETS)
74 const int action{message.GetParam1()};
75 if (action == ACTION_SELECT_ITEM || action == ACTION_MOUSE_LEFT_CLICK)
77 if (UpdateSelectedAsset())
78 SET_CONTROL_FOCUS(CONTROL_BUTTON_PLAY, 0);
81 else if (control == CONTROL_BUTTON_PLAY)
83 Play();
85 else if (control == CONTROL_BUTTON_REMOVE)
87 Remove();
89 else if (control == CONTROL_BUTTON_CHOOSE_ART)
91 ChooseArt();
93 break;
97 return CGUIDialog::OnMessage(message);
100 bool CGUIDialogVideoManager::OnAction(const CAction& action)
102 const int actionId{action.GetID()};
103 if (actionId == ACTION_MOVE_DOWN || actionId == ACTION_MOVE_UP || actionId == ACTION_PAGE_DOWN ||
104 actionId == ACTION_PAGE_UP || actionId == ACTION_FIRST_PAGE || actionId == ACTION_LAST_PAGE)
106 if (GetFocusedControlID() == CONTROL_LIST_ASSETS)
108 CGUIDialog::OnAction(action);
109 return UpdateSelectedAsset();
113 return CGUIDialog::OnAction(action);
116 void CGUIDialogVideoManager::OnInitWindow()
118 if (!m_database.IsOpen() && !m_database.Open())
119 CLog::LogF(LOGERROR, "Failed to open video database!");
121 CGUIDialog::OnInitWindow();
123 SET_CONTROL_LABEL(CONTROL_LABEL_TITLE,
124 StringUtils::Format(g_localizeStrings.Get(GetHeadingId()),
125 m_videoAsset->GetVideoInfoTag()->GetTitle()));
127 CGUIMessage msg{GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST_ASSETS, 0, 0, m_videoAssetsList.get()};
128 OnMessage(msg);
130 UpdateControls();
133 void CGUIDialogVideoManager::OnDeinitWindow(int nextWindowID)
135 CGUIDialog::OnDeinitWindow(nextWindowID);
136 m_database.Close();
139 void CGUIDialogVideoManager::Clear()
141 m_videoAssetsList->Clear();
144 void CGUIDialogVideoManager::UpdateButtons()
146 // Enabled if list not empty
147 if (!m_videoAssetsList->IsEmpty())
149 CONTROL_ENABLE(CONTROL_BUTTON_CHOOSE_ART);
150 CONTROL_ENABLE(CONTROL_BUTTON_REMOVE);
151 CONTROL_ENABLE(CONTROL_BUTTON_PLAY);
153 SET_CONTROL_FOCUS(CONTROL_LIST_ASSETS, 0);
155 else
157 CONTROL_DISABLE(CONTROL_BUTTON_CHOOSE_ART);
158 CONTROL_DISABLE(CONTROL_BUTTON_REMOVE);
159 CONTROL_DISABLE(CONTROL_BUTTON_PLAY);
163 void CGUIDialogVideoManager::UpdateAssetsList()
165 // find new item in list and select it
166 for (int i = 0; i < m_videoAssetsList->Size(); ++i)
168 if (m_videoAssetsList->Get(i)->GetVideoInfoTag()->m_iDbId ==
169 m_selectedVideoAsset->GetVideoInfoTag()->m_iDbId)
171 CONTROL_SELECT_ITEM(CONTROL_LIST_ASSETS, i);
172 break;
177 bool CGUIDialogVideoManager::UpdateSelectedAsset()
179 CGUIMessage msg{GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_LIST_ASSETS};
180 OnMessage(msg);
182 const int item{msg.GetParam1()};
183 if (item >= 0 && item < m_videoAssetsList->Size())
185 m_selectedVideoAsset = m_videoAssetsList->Get(item);
186 UpdateControls();
187 return true;
189 return false;
192 void CGUIDialogVideoManager::DisableRemove()
194 CONTROL_DISABLE(CONTROL_BUTTON_REMOVE);
197 void CGUIDialogVideoManager::EnableRemove()
199 CONTROL_ENABLE(CONTROL_BUTTON_REMOVE);
202 void CGUIDialogVideoManager::UpdateControls()
204 UpdateButtons();
205 UpdateAssetsList();
208 void CGUIDialogVideoManager::Refresh()
210 if (!m_database.IsOpen() && !m_database.Open())
211 CLog::LogF(LOGERROR, "Failed to open video database!");
213 Clear();
215 const int dbId{m_videoAsset->GetVideoInfoTag()->m_iDbId};
216 const MediaType mediaType{m_videoAsset->GetVideoInfoTag()->m_type};
217 const VideoDbContentType itemType{m_videoAsset->GetVideoContentType()};
219 //! @todo db refactor: should not be versions, but assets
220 m_database.GetVideoVersions(itemType, dbId, *m_videoAssetsList, GetVideoAssetType());
221 m_videoAssetsList->SetContent(CMediaTypes::ToPlural(mediaType));
223 CVideoThumbLoader loader;
225 for (auto& item : *m_videoAssetsList)
227 item->SetProperty("noartfallbacktoowner", true);
228 loader.LoadItem(item.get());
231 CGUIMessage msg{GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST_ASSETS, 0, 0, m_videoAssetsList.get()};
232 OnMessage(msg);
235 void CGUIDialogVideoManager::SetVideoAsset(const std::shared_ptr<CFileItem>& item)
237 if (!item || !item->HasVideoInfoTag() || item->GetVideoInfoTag()->m_type != MediaTypeMovie)
239 CLog::LogF(LOGERROR, "Unexpected video item!");
240 return;
243 m_videoAsset = item;
245 Refresh();
248 void CGUIDialogVideoManager::CloseAll()
250 // close our dialog
251 Close(true);
253 // close the video info dialog if exists
254 CGUIDialogVideoInfo* dialog{
255 CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogVideoInfo>(
256 WINDOW_DIALOG_VIDEO_INFO)};
257 if (dialog)
258 dialog->Close(true);
261 namespace
263 class CVideoPlayActionProcessor : public VIDEO::GUILIB::CVideoPlayActionProcessorBase
265 public:
266 explicit CVideoPlayActionProcessor(const std::shared_ptr<CFileItem>& item)
267 : CVideoPlayActionProcessorBase(item)
271 protected:
272 bool OnResumeSelected() override
274 m_item->SetStartOffset(STARTOFFSET_RESUME);
275 Play();
276 return true;
279 bool OnPlaySelected() override
281 Play();
282 return true;
285 private:
286 void Play()
288 m_item->SetProperty("playlist_type_hint", static_cast<int>(PLAYLIST::Id::TYPE_VIDEO));
289 const ContentUtils::PlayMode mode{m_item->GetProperty("CheckAutoPlayNextItem").asBoolean()
290 ? ContentUtils::PlayMode::CHECK_AUTO_PLAY_NEXT_ITEM
291 : ContentUtils::PlayMode::PLAY_ONLY_THIS};
292 VIDEO::UTILS::PlayItem(m_item, "", mode);
295 } // unnamed namespace
297 void CGUIDialogVideoManager::Play()
299 CloseAll();
301 CVideoPlayActionProcessor proc{m_selectedVideoAsset};
302 proc.ProcessDefaultAction();
305 void CGUIDialogVideoManager::Remove()
307 // confirm to remove
308 if (!CGUIDialogYesNo::ShowAndGetInput(
309 CVariant(40018),
310 StringUtils::Format(g_localizeStrings.Get(40020),
311 m_selectedVideoAsset->GetVideoInfoTag()->GetAssetInfo().GetTitle())))
313 return;
316 m_database.DeleteVideoAsset(m_selectedVideoAsset->GetVideoInfoTag()->m_iDbId);
318 // refresh data and controls
319 Refresh();
320 RefreshSelectedVideoAsset();
321 UpdateControls();
324 void CGUIDialogVideoManager::Rename()
326 const int idAsset{
327 ChooseVideoAsset(m_videoAsset, GetVideoAssetType(), m_selectedVideoAsset->m_strTitle)};
328 if (idAsset != -1)
330 //! @todo db refactor: should not be version, but asset
331 m_database.SetVideoVersion(m_selectedVideoAsset->GetVideoInfoTag()->m_iDbId, idAsset);
334 // refresh data and controls
335 Refresh();
336 UpdateControls();
339 void CGUIDialogVideoManager::ChooseArt()
341 if (!CGUIDialogVideoInfo::ChooseAndManageVideoItemArtwork(m_selectedVideoAsset))
342 return;
344 // refresh data and controls
345 Refresh();
346 UpdateControls();
349 void CGUIDialogVideoManager::SetSelectedVideoAsset(const std::shared_ptr<CFileItem>& asset)
351 const int dbId{asset->GetVideoInfoTag()->m_iDbId};
352 const auto it{std::find_if(m_videoAssetsList->cbegin(), m_videoAssetsList->cend(),
353 [dbId](const auto& entry)
354 { return entry->GetVideoInfoTag()->m_iDbId == dbId; })};
355 if (it != m_videoAssetsList->cend())
356 m_selectedVideoAsset = (*it);
357 else
358 CLog::LogF(LOGERROR, "Item to select not found in asset list!");
360 UpdateControls();
363 int CGUIDialogVideoManager::ChooseVideoAsset(const std::shared_ptr<CFileItem>& item,
364 VideoAssetType assetType,
365 const std::string& defaultName)
367 if (!item || !item->HasVideoInfoTag())
368 return -1;
370 const VideoDbContentType itemType{item->GetVideoContentType()};
371 if (itemType != VideoDbContentType::MOVIES)
372 return -1;
374 int dialogHeadingMsgId{};
375 int dialogButtonMsgId{};
376 int dialogNewHeadingMsgId{};
378 switch (assetType)
380 case VideoAssetType::VERSION:
381 dialogHeadingMsgId = 40215;
382 dialogButtonMsgId = 40216;
383 dialogNewHeadingMsgId = 40217;
384 break;
385 case VideoAssetType::EXTRA:
386 dialogHeadingMsgId = 40218;
387 dialogButtonMsgId = 40219;
388 dialogNewHeadingMsgId = 40220;
389 break;
390 default:
391 CLog::LogF(LOGERROR, "Unknown asset type ({})", static_cast<int>(assetType));
392 return -1;
395 CVideoDatabase videodb;
396 if (!videodb.Open())
398 CLog::LogF(LOGERROR, "Failed to open video database!");
399 return -1;
402 CGUIDialogSelect* dialog{CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(
403 WINDOW_DIALOG_SELECT)};
404 if (!dialog)
406 CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT instance!");
407 return -1;
410 //! @todo db refactor: should not be version, but asset
411 CFileItemList list;
412 videodb.GetVideoVersionTypes(itemType, assetType, list);
414 int assetId{-1};
415 while (true)
417 std::string assetTitle;
419 dialog->Reset();
420 dialog->SetItems(list);
421 dialog->SetHeading(dialogHeadingMsgId);
422 dialog->EnableButton(true, dialogButtonMsgId);
423 dialog->Open();
425 if (dialog->IsButtonPressed())
427 // create a new asset
428 assetTitle = defaultName;
429 if (CGUIKeyboardFactory::ShowAndGetInput(assetTitle,
430 g_localizeStrings.Get(dialogNewHeadingMsgId), false))
432 assetTitle = StringUtils::Trim(assetTitle);
433 //! @todo db refactor: should not be version, but asset
434 assetId = videodb.AddVideoVersionType(assetTitle, VideoAssetTypeOwner::USER, assetType);
437 else if (dialog->IsConfirmed())
439 const std::shared_ptr<CFileItem> selectedItem{dialog->GetSelectedFileItem()};
440 assetId = selectedItem->GetVideoInfoTag()->GetAssetInfo().GetId();
441 assetTitle = selectedItem->GetVideoInfoTag()->GetAssetInfo().GetTitle();
443 else
444 return -1;
446 if (assetId < 0)
447 return -1;
449 const int dbId{item->GetVideoInfoTag()->m_iDbId};
451 //! @todo db refactor: should not be versions, but assets
452 CFileItemList assets;
453 videodb.GetVideoVersions(itemType, dbId, assets, assetType);
455 // the selected video asset already exists
456 if (std::any_of(assets.cbegin(), assets.cend(),
457 [assetId](const std::shared_ptr<CFileItem>& asset)
458 { return asset->GetVideoInfoTag()->m_iDbId == assetId; }))
460 CGUIDialogOK::ShowAndGetInput(CVariant{40005},
461 StringUtils::Format(g_localizeStrings.Get(40007), assetTitle));
463 else
464 break;
467 return assetId;
470 void CGUIDialogVideoManager::AppendItemFolderToFileBrowserSources(
471 std::vector<CMediaSource>& sources)
473 const std::string itemDir{URIUtils::GetParentPath(m_videoAsset->GetDynPath())};
474 if (!itemDir.empty() && XFILE::CDirectory::Exists(itemDir))
476 CMediaSource itemSource{};
477 itemSource.strName = g_localizeStrings.Get(36041); // * Item folder
478 itemSource.strPath = itemDir;
479 sources.emplace_back(itemSource);
483 void CGUIDialogVideoManager::RefreshSelectedVideoAsset()
485 if (!m_selectedVideoAsset || !m_selectedVideoAsset->HasVideoInfoTag() ||
486 !m_videoAssetsList->Size())
488 m_selectedVideoAsset = std::make_shared<CFileItem>();
489 return;
492 const int dbId{m_selectedVideoAsset->GetVideoInfoTag()->m_iDbId};
493 const auto it{std::find_if(m_videoAssetsList->cbegin(), m_videoAssetsList->cend(),
494 [dbId](const auto& entry)
495 { return entry->GetVideoInfoTag()->m_iDbId == dbId; })};
497 if (it == m_videoAssetsList->cend())
498 m_selectedVideoAsset = m_videoAssetsList->Get(0);