[video] Load thumbs async for version chooser
[xbmc.git] / xbmc / video / guilib / VideoVersionHelper.cpp
blobe6ece8f03c28cbec15c3c504d58045b94b745d18
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 "VideoVersionHelper.h"
11 #include "FileItem.h"
12 #include "ServiceBroker.h"
13 #include "URL.h"
14 #include "dialogs/GUIDialogSelect.h"
15 #include "guilib/GUIComponent.h"
16 #include "guilib/GUIWindowManager.h"
17 #include "guilib/LocalizeStrings.h"
18 #include "settings/Settings.h"
19 #include "settings/SettingsComponent.h"
20 #include "settings/lib/Setting.h"
21 #include "utils/StringUtils.h"
22 #include "utils/log.h"
23 #include "video/VideoDatabase.h"
24 #include "video/VideoManagerTypes.h"
25 #include "video/VideoThumbLoader.h"
27 using namespace VIDEO::GUILIB;
29 namespace
31 class CVideoChooser
33 public:
34 explicit CVideoChooser(const std::shared_ptr<const CFileItem>& item) : m_item(item) {}
35 virtual ~CVideoChooser() = default;
37 void EnableTypeSwitch(bool enable) { m_enableTypeSwitch = enable; }
38 void SetInitialAssetType(VideoAssetType type) { m_initialAssetType = type; }
40 std::shared_ptr<const CFileItem> ChooseVideo();
42 private:
43 CVideoChooser() = delete;
44 std::shared_ptr<const CFileItem> ChooseVideoVersion();
45 std::shared_ptr<const CFileItem> ChooseVideoExtra();
46 std::shared_ptr<const CFileItem> ChooseVideo(CGUIDialogSelect& dialog,
47 int headingId,
48 int buttonId,
49 CFileItemList& itemsToDisplay,
50 const CFileItemList& itemsToSwitchTo);
52 const std::shared_ptr<const CFileItem> m_item;
53 bool m_enableTypeSwitch{false};
54 VideoAssetType m_initialAssetType{VideoAssetType::UNKNOWN};
55 bool m_switchType{false};
56 CFileItemList m_videoVersions;
57 CFileItemList m_videoExtras;
60 std::shared_ptr<const CFileItem> CVideoChooser::ChooseVideo()
62 m_switchType = false;
63 m_videoVersions.Clear();
64 m_videoExtras.Clear();
66 std::shared_ptr<const CFileItem> result;
67 if (m_enableTypeSwitch && !m_item->HasVideoVersions() && !m_item->HasVideoExtras())
68 return result;
70 if (!m_enableTypeSwitch && m_initialAssetType == VideoAssetType::VERSION &&
71 !m_item->HasVideoVersions())
72 return result;
74 if (!m_enableTypeSwitch && m_initialAssetType == VideoAssetType::EXTRA &&
75 !m_item->HasVideoExtras())
76 return result;
78 CVideoDatabase db;
79 if (!db.Open())
81 CLog::LogF(LOGERROR, "Unable to open video database!");
82 return result;
85 if (m_initialAssetType == VideoAssetType::VERSION || m_enableTypeSwitch)
87 db.GetAssetsForVideo(m_item->GetVideoContentType(), m_item->GetVideoInfoTag()->m_iDbId,
88 VideoAssetType::VERSION, m_videoVersions);
90 // find default version item in list and select it
91 for (const auto& item : m_videoVersions)
93 item->Select(item->GetVideoInfoTag()->IsDefaultVideoVersion());
97 if (m_initialAssetType == VideoAssetType::EXTRA || m_enableTypeSwitch)
98 db.GetAssetsForVideo(m_item->GetVideoContentType(), m_item->GetVideoInfoTag()->m_iDbId,
99 VideoAssetType::EXTRA, m_videoExtras);
101 VideoAssetType itemType{m_initialAssetType};
102 while (true)
104 if (itemType == VideoAssetType::VERSION)
106 result = ChooseVideoVersion();
107 itemType = VideoAssetType::EXTRA;
109 else
111 result = ChooseVideoExtra();
112 itemType = VideoAssetType::VERSION;
115 if (!m_switchType)
116 break;
118 // switch type button pressed. Re-open, this time with the "other" type to select.
120 return result;
123 std::shared_ptr<const CFileItem> CVideoChooser::ChooseVideoVersion()
125 CGUIDialogSelect* dialog{CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(
126 WINDOW_DIALOG_SELECT_VIDEO_VERSION)};
127 if (!dialog)
129 CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT_VIDEO_VERSION dialog instance!");
130 return {};
133 return ChooseVideo(*dialog, 40208 /* Choose version */, 40211 /* Extras */, m_videoVersions,
134 m_videoExtras);
137 std::shared_ptr<const CFileItem> CVideoChooser::ChooseVideoExtra()
139 CGUIDialogSelect* dialog{CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(
140 WINDOW_DIALOG_SELECT_VIDEO_EXTRA)};
141 if (!dialog)
143 CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT_VIDEO_EXTRA dialog instance!");
144 return {};
147 return ChooseVideo(*dialog, 40214 /* Choose extra */, 40210 /* Versions */, m_videoExtras,
148 m_videoVersions);
151 std::shared_ptr<const CFileItem> CVideoChooser::ChooseVideo(CGUIDialogSelect& dialog,
152 int headingId,
153 int buttonId,
154 CFileItemList& itemsToDisplay,
155 const CFileItemList& itemsToSwitchTo)
157 CVideoThumbLoader thumbLoader;
158 thumbLoader.Load(itemsToDisplay);
159 for (auto& item : itemsToDisplay)
160 item->SetLabel2(item->GetVideoInfoTag()->m_strFileNameAndPath);
162 dialog.Reset();
164 const std::string heading{
165 StringUtils::Format(g_localizeStrings.Get(headingId), m_item->GetVideoInfoTag()->GetTitle())};
166 dialog.SetHeading(heading);
168 dialog.EnableButton(m_enableTypeSwitch && !itemsToSwitchTo.IsEmpty(), buttonId);
169 dialog.SetUseDetails(true);
170 dialog.SetMultiSelection(false);
171 dialog.SetItems(itemsToDisplay);
173 dialog.Open();
175 if (thumbLoader.IsLoading())
176 thumbLoader.StopThread();
178 m_switchType = dialog.IsButtonPressed();
179 if (dialog.IsConfirmed())
180 return dialog.GetSelectedFileItem();
182 return {};
184 } // unnamed namespace
186 std::shared_ptr<CFileItem> CVideoVersionHelper::ChooseVideoFromAssets(
187 const std::shared_ptr<CFileItem>& item)
189 std::shared_ptr<const CFileItem> video;
191 VideoAssetType assetType{static_cast<int>(
192 item->GetProperty("video_asset_type").asInteger(static_cast<int>(VideoAssetType::UNKNOWN)))};
193 bool allAssetTypes{false};
194 bool hasMultipleChoices{false};
196 switch (assetType)
198 case VideoAssetType::UNKNOWN:
199 // asset type not provided means all types are allowed and the user can switch between types
200 allAssetTypes = true;
201 if (item->HasVideoVersions() || item->HasVideoExtras())
202 hasMultipleChoices = true;
203 break;
205 case VideoAssetType::VERSION:
206 if (item->HasVideoVersions())
207 hasMultipleChoices = true;
208 break;
210 case VideoAssetType::EXTRA:
211 if (item->HasVideoExtras())
212 hasMultipleChoices = true;
213 break;
215 default:
216 CLog::LogF(LOGERROR, "unknown asset type ({})", static_cast<int>(assetType));
217 return {};
220 if (hasMultipleChoices)
222 if (!item->GetProperty("needs_resolved_video_asset").asBoolean(false))
224 // auto select the default video version
225 const auto settings{CServiceBroker::GetSettingsComponent()->GetSettings()};
226 if (settings->GetBool(CSettings::SETTING_MYVIDEOS_SELECTDEFAULTVERSION))
228 if (item->GetVideoInfoTag()->IsDefaultVideoVersion())
230 video = std::make_shared<const CFileItem>(*item);
232 else
234 CVideoDatabase db;
235 if (!db.Open())
237 CLog::LogF(LOGERROR, "Unable to open video database!");
239 else
241 CFileItem defaultVersion;
242 if (!db.GetDefaultVersionForVideo(item->GetVideoContentType(),
243 item->GetVideoInfoTag()->m_iDbId, defaultVersion))
244 CLog::LogF(LOGERROR, "Unable to get default version from video database!");
245 else
246 video = std::make_shared<const CFileItem>(defaultVersion);
252 if (!video && (item->GetProperty("needs_resolved_video_asset").asBoolean(false) ||
253 !item->GetProperty("has_resolved_video_asset").asBoolean(false)))
255 CVideoChooser chooser{item};
257 if (allAssetTypes)
259 chooser.EnableTypeSwitch(true);
260 chooser.SetInitialAssetType(VideoAssetType::VERSION);
262 else
264 chooser.EnableTypeSwitch(false);
265 chooser.SetInitialAssetType(assetType);
268 const auto result{chooser.ChooseVideo()};
269 if (result)
270 video = result;
271 else
272 return {};
276 if (video)
277 return std::make_shared<CFileItem>(*video);
279 return item;
282 bool VIDEO::IsVideoAssetFile(const CFileItem& item)
284 if (item.m_bIsFolder || !item.IsVideoDb())
285 return false;
287 // @todo maybe in the future look for prefix videodb://movies/videoversions in path instead
288 // @todo better encoding of video assets as path, they won't always be tied with movies.
289 const CURL itemUrl{item.GetPath()};
290 if (itemUrl.HasOption("videoversionid"))
291 return true;
293 return false;