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.
9 #include "GUIDialogVideoManager.h"
12 #include "GUIUserMessages.h"
13 #include "MediaSource.h"
14 #include "ServiceBroker.h"
15 #include "dialogs/GUIDialogOK.h"
16 #include "dialogs/GUIDialogSelect.h"
17 #include "dialogs/GUIDialogYesNo.h"
18 #include "filesystem/Directory.h"
19 #include "guilib/GUIComponent.h"
20 #include "guilib/GUIKeyboardFactory.h"
21 #include "guilib/GUIWindowManager.h"
22 #include "guilib/LocalizeStrings.h"
23 #include "input/actions/Action.h"
24 #include "input/actions/ActionIDs.h"
25 #include "playlists/PlayListTypes.h"
26 #include "utils/StringUtils.h"
27 #include "utils/URIUtils.h"
28 #include "utils/log.h"
29 #include "video/VideoManagerTypes.h"
30 #include "video/VideoThumbLoader.h"
31 #include "video/VideoUtils.h"
32 #include "video/dialogs/GUIDialogVideoInfo.h"
33 #include "video/guilib/VideoPlayActionProcessor.h"
38 static constexpr unsigned int CONTROL_LABEL_TITLE
= 2;
40 static constexpr unsigned int CONTROL_BUTTON_PLAY
= 21;
41 static constexpr unsigned int CONTROL_BUTTON_REMOVE
= 26;
42 static constexpr unsigned int CONTROL_BUTTON_CHOOSE_ART
= 27;
44 static constexpr unsigned int CONTROL_LIST_ASSETS
= 50;
46 CGUIDialogVideoManager::CGUIDialogVideoManager(int windowId
)
47 : CGUIDialog(windowId
, "DialogVideoManager.xml"),
48 m_videoAsset(std::make_shared
<CFileItem
>()),
49 m_videoAssetsList(std::make_unique
<CFileItemList
>()),
50 m_selectedVideoAsset(std::make_shared
<CFileItem
>())
52 m_loadType
= KEEP_IN_MEMORY
;
54 if (!m_database
.Open())
55 CLog::LogF(LOGERROR
, "Failed to open video database!");
58 bool CGUIDialogVideoManager::OnMessage(CGUIMessage
& message
)
60 switch (message
.GetMessage())
62 case GUI_MSG_WINDOW_DEINIT
:
70 const int control
{message
.GetSenderId()};
71 if (control
== CONTROL_LIST_ASSETS
)
73 const int action
{message
.GetParam1()};
74 if (action
== ACTION_SELECT_ITEM
|| action
== ACTION_MOUSE_LEFT_CLICK
)
76 if (UpdateSelectedAsset())
77 SET_CONTROL_FOCUS(CONTROL_BUTTON_PLAY
, 0);
80 else if (control
== CONTROL_BUTTON_PLAY
)
84 else if (control
== CONTROL_BUTTON_REMOVE
)
88 else if (control
== CONTROL_BUTTON_CHOOSE_ART
)
96 return CGUIDialog::OnMessage(message
);
99 bool CGUIDialogVideoManager::OnAction(const CAction
& action
)
101 const int actionId
{action
.GetID()};
102 if (actionId
== ACTION_MOVE_DOWN
|| actionId
== ACTION_MOVE_UP
|| actionId
== ACTION_PAGE_DOWN
||
103 actionId
== ACTION_PAGE_UP
|| actionId
== ACTION_FIRST_PAGE
|| actionId
== ACTION_LAST_PAGE
)
105 if (GetFocusedControlID() == CONTROL_LIST_ASSETS
)
107 CGUIDialog::OnAction(action
);
108 return UpdateSelectedAsset();
112 return CGUIDialog::OnAction(action
);
115 void CGUIDialogVideoManager::OnInitWindow()
117 CGUIDialog::OnInitWindow();
119 SET_CONTROL_LABEL(CONTROL_LABEL_TITLE
,
120 StringUtils::Format(g_localizeStrings
.Get(GetHeadingId()),
121 m_videoAsset
->GetVideoInfoTag()->GetTitle()));
123 CGUIMessage msg
{GUI_MSG_LABEL_BIND
, GetID(), CONTROL_LIST_ASSETS
, 0, 0, m_videoAssetsList
.get()};
129 void CGUIDialogVideoManager::Clear()
131 m_videoAssetsList
->Clear();
134 void CGUIDialogVideoManager::UpdateButtons()
136 // Enabled if list not empty
137 if (!m_videoAssetsList
->IsEmpty())
139 CONTROL_ENABLE(CONTROL_BUTTON_CHOOSE_ART
);
140 CONTROL_ENABLE(CONTROL_BUTTON_REMOVE
);
141 CONTROL_ENABLE(CONTROL_BUTTON_PLAY
);
143 SET_CONTROL_FOCUS(CONTROL_LIST_ASSETS
, 0);
147 CONTROL_DISABLE(CONTROL_BUTTON_CHOOSE_ART
);
148 CONTROL_DISABLE(CONTROL_BUTTON_REMOVE
);
149 CONTROL_DISABLE(CONTROL_BUTTON_PLAY
);
153 void CGUIDialogVideoManager::UpdateAssetsList()
155 // find new item in list and select it
156 for (int i
= 0; i
< m_videoAssetsList
->Size(); ++i
)
158 if (m_videoAssetsList
->Get(i
)->GetVideoInfoTag()->m_iDbId
==
159 m_selectedVideoAsset
->GetVideoInfoTag()->m_iDbId
)
161 CONTROL_SELECT_ITEM(CONTROL_LIST_ASSETS
, i
);
167 bool CGUIDialogVideoManager::UpdateSelectedAsset()
169 CGUIMessage msg
{GUI_MSG_ITEM_SELECTED
, GetID(), CONTROL_LIST_ASSETS
};
172 const int item
{msg
.GetParam1()};
173 if (item
>= 0 && item
< m_videoAssetsList
->Size())
175 m_selectedVideoAsset
= m_videoAssetsList
->Get(item
);
182 void CGUIDialogVideoManager::DisableRemove()
184 CONTROL_DISABLE(CONTROL_BUTTON_REMOVE
);
187 void CGUIDialogVideoManager::EnableRemove()
189 CONTROL_ENABLE(CONTROL_BUTTON_REMOVE
);
192 void CGUIDialogVideoManager::UpdateControls()
198 void CGUIDialogVideoManager::Refresh()
202 const int dbId
{m_videoAsset
->GetVideoInfoTag()->m_iDbId
};
203 const MediaType mediaType
{m_videoAsset
->GetVideoInfoTag()->m_type
};
204 const VideoDbContentType itemType
{m_videoAsset
->GetVideoContentType()};
206 //! @todo db refactor: should not be versions, but assets
207 m_database
.GetVideoVersions(itemType
, dbId
, *m_videoAssetsList
, GetVideoAssetType());
208 m_videoAssetsList
->SetContent(CMediaTypes::ToPlural(mediaType
));
210 CVideoThumbLoader loader
;
212 for (auto& item
: *m_videoAssetsList
)
214 item
->SetProperty("noartfallbacktoowner", true);
215 loader
.LoadItem(item
.get());
218 CGUIMessage msg
{GUI_MSG_LABEL_BIND
, GetID(), CONTROL_LIST_ASSETS
, 0, 0, m_videoAssetsList
.get()};
222 void CGUIDialogVideoManager::SetVideoAsset(const std::shared_ptr
<CFileItem
>& item
)
224 if (!item
|| !item
->HasVideoInfoTag() || item
->GetVideoInfoTag()->m_type
!= MediaTypeMovie
)
226 CLog::LogF(LOGERROR
, "Unexpected video item!");
235 void CGUIDialogVideoManager::CloseAll()
240 // close the video info dialog if exists
241 CGUIDialogVideoInfo
* dialog
{
242 CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogVideoInfo
>(
243 WINDOW_DIALOG_VIDEO_INFO
)};
250 class CVideoPlayActionProcessor
: public VIDEO::GUILIB::CVideoPlayActionProcessorBase
253 explicit CVideoPlayActionProcessor(const std::shared_ptr
<CFileItem
>& item
)
254 : CVideoPlayActionProcessorBase(item
)
259 bool OnResumeSelected() override
261 m_item
->SetStartOffset(STARTOFFSET_RESUME
);
266 bool OnPlaySelected() override
275 m_item
->SetProperty("playlist_type_hint", PLAYLIST::TYPE_VIDEO
);
276 const ContentUtils::PlayMode mode
{m_item
->GetProperty("CheckAutoPlayNextItem").asBoolean()
277 ? ContentUtils::PlayMode::CHECK_AUTO_PLAY_NEXT_ITEM
278 : ContentUtils::PlayMode::PLAY_ONLY_THIS
};
279 VIDEO_UTILS::PlayItem(m_item
, "", mode
);
282 } // unnamed namespace
284 void CGUIDialogVideoManager::Play()
288 CVideoPlayActionProcessor proc
{m_selectedVideoAsset
};
289 proc
.ProcessDefaultAction();
292 void CGUIDialogVideoManager::Remove()
295 if (!CGUIDialogYesNo::ShowAndGetInput(
297 StringUtils::Format(g_localizeStrings
.Get(40020),
298 m_selectedVideoAsset
->GetVideoInfoTag()->GetAssetInfo().GetTitle())))
303 //! @todo db refactor: should not be version, but asset
304 m_database
.RemoveVideoVersion(m_selectedVideoAsset
->GetVideoInfoTag()->m_iDbId
);
306 // refresh data and controls
311 void CGUIDialogVideoManager::Rename()
314 ChooseVideoAsset(m_videoAsset
, GetVideoAssetType(), m_selectedVideoAsset
->m_strTitle
)};
317 //! @todo db refactor: should not be version, but asset
318 m_database
.SetVideoVersion(m_selectedVideoAsset
->GetVideoInfoTag()->m_iDbId
, idAsset
);
321 // refresh data and controls
326 void CGUIDialogVideoManager::ChooseArt()
328 if (!CGUIDialogVideoInfo::ChooseAndManageVideoItemArtwork(m_selectedVideoAsset
))
331 // refresh data and controls
336 void CGUIDialogVideoManager::SetSelectedVideoAsset(const std::shared_ptr
<CFileItem
>& asset
)
338 const int dbId
{asset
->GetVideoInfoTag()->m_iDbId
};
339 const auto it
{std::find_if(m_videoAssetsList
->cbegin(), m_videoAssetsList
->cend(),
340 [dbId
](const auto& entry
)
341 { return entry
->GetVideoInfoTag()->m_iDbId
== dbId
; })};
342 if (it
!= m_videoAssetsList
->cend())
343 m_selectedVideoAsset
= (*it
);
345 CLog::LogF(LOGERROR
, "Item to select not found in asset list!");
350 int CGUIDialogVideoManager::ChooseVideoAsset(const std::shared_ptr
<CFileItem
>& item
,
351 VideoAssetType assetType
,
352 const std::string
& defaultName
)
354 if (!item
|| !item
->HasVideoInfoTag())
357 const VideoDbContentType itemType
{item
->GetVideoContentType()};
358 if (itemType
!= VideoDbContentType::MOVIES
)
361 int dialogHeadingMsgId
{};
362 int dialogButtonMsgId
{};
363 int dialogNewHeadingMsgId
{};
367 case VideoAssetType::VERSION
:
368 dialogHeadingMsgId
= 40215;
369 dialogButtonMsgId
= 40216;
370 dialogNewHeadingMsgId
= 40217;
372 case VideoAssetType::EXTRA
:
373 dialogHeadingMsgId
= 40218;
374 dialogButtonMsgId
= 40219;
375 dialogNewHeadingMsgId
= 40220;
378 CLog::LogF(LOGERROR
, "Unknown asset type ({})", static_cast<int>(assetType
));
382 CVideoDatabase videodb
;
385 CLog::LogF(LOGERROR
, "Failed to open video database!");
389 CGUIDialogSelect
* dialog
{CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogSelect
>(
390 WINDOW_DIALOG_SELECT
)};
393 CLog::LogF(LOGERROR
, "Unable to get WINDOW_DIALOG_SELECT instance!");
397 //! @todo db refactor: should not be version, but asset
399 videodb
.GetVideoVersionTypes(itemType
, assetType
, list
);
404 std::string assetTitle
;
407 dialog
->SetItems(list
);
408 dialog
->SetHeading(dialogHeadingMsgId
);
409 dialog
->EnableButton(true, dialogButtonMsgId
);
412 if (dialog
->IsButtonPressed())
414 // create a new asset
415 assetTitle
= defaultName
;
416 if (CGUIKeyboardFactory::ShowAndGetInput(assetTitle
,
417 g_localizeStrings
.Get(dialogNewHeadingMsgId
), false))
419 assetTitle
= StringUtils::Trim(assetTitle
);
420 //! @todo db refactor: should not be version, but asset
421 assetId
= videodb
.AddVideoVersionType(assetTitle
, VideoAssetTypeOwner::USER
, assetType
);
424 else if (dialog
->IsConfirmed())
426 const std::shared_ptr
<CFileItem
> selectedItem
{dialog
->GetSelectedFileItem()};
427 assetId
= selectedItem
->GetVideoInfoTag()->GetAssetInfo().GetId();
428 assetTitle
= selectedItem
->GetVideoInfoTag()->GetAssetInfo().GetTitle();
436 const int dbId
{item
->GetVideoInfoTag()->m_iDbId
};
438 //! @todo db refactor: should not be versions, but assets
439 CFileItemList assets
;
440 videodb
.GetVideoVersions(itemType
, dbId
, assets
, assetType
);
442 // the selected video asset already exists
443 if (std::any_of(assets
.cbegin(), assets
.cend(),
444 [assetId
](const std::shared_ptr
<CFileItem
>& asset
)
445 { return asset
->GetVideoInfoTag()->m_iDbId
== assetId
; }))
447 CGUIDialogOK::ShowAndGetInput(CVariant
{40005},
448 StringUtils::Format(g_localizeStrings
.Get(40007), assetTitle
));
457 void CGUIDialogVideoManager::AppendItemFolderToFileBrowserSources(
458 std::vector
<CMediaSource
>& sources
)
460 const std::string itemDir
{URIUtils::GetParentPath(m_videoAsset
->GetDynPath())};
461 if (!itemDir
.empty() && XFILE::CDirectory::Exists(itemDir
))
463 CMediaSource itemSource
{};
464 itemSource
.strName
= g_localizeStrings
.Get(36041); // * Item folder
465 itemSource
.strPath
= itemDir
;
466 sources
.emplace_back(itemSource
);