summaryrefslogtreecommitdiffstats
path: root/xbmc/guilib/guiinfo
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/guilib/guiinfo')
-rw-r--r--xbmc/guilib/guiinfo/AddonsGUIInfo.cpp279
-rw-r--r--xbmc/guilib/guiinfo/AddonsGUIInfo.h37
-rw-r--r--xbmc/guilib/guiinfo/CMakeLists.txt42
-rw-r--r--xbmc/guilib/guiinfo/GUIControlsGUIInfo.cpp814
-rw-r--r--xbmc/guilib/guiinfo/GUIControlsGUIInfo.h56
-rw-r--r--xbmc/guilib/guiinfo/GUIInfo.cpp33
-rw-r--r--xbmc/guilib/guiinfo/GUIInfo.h110
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoBool.cpp41
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoBool.h46
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoColor.cpp69
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoColor.h53
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoHelper.cpp205
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoHelper.h43
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoLabel.cpp337
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoLabel.h146
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoLabels.h985
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoProvider.h49
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoProviders.cpp122
-rw-r--r--xbmc/guilib/guiinfo/GUIInfoProviders.h157
-rw-r--r--xbmc/guilib/guiinfo/GamesGUIInfo.cpp87
-rw-r--r--xbmc/guilib/guiinfo/GamesGUIInfo.h37
-rw-r--r--xbmc/guilib/guiinfo/IGUIInfoProvider.h97
-rw-r--r--xbmc/guilib/guiinfo/LibraryGUIInfo.cpp290
-rw-r--r--xbmc/guilib/guiinfo/LibraryGUIInfo.h59
-rw-r--r--xbmc/guilib/guiinfo/MusicGUIInfo.cpp713
-rw-r--r--xbmc/guilib/guiinfo/MusicGUIInfo.h46
-rw-r--r--xbmc/guilib/guiinfo/PicturesGUIInfo.cpp259
-rw-r--r--xbmc/guilib/guiinfo/PicturesGUIInfo.h45
-rw-r--r--xbmc/guilib/guiinfo/PlayerGUIInfo.cpp726
-rw-r--r--xbmc/guilib/guiinfo/PlayerGUIInfo.h93
-rw-r--r--xbmc/guilib/guiinfo/SkinGUIInfo.cpp140
-rw-r--r--xbmc/guilib/guiinfo/SkinGUIInfo.h37
-rw-r--r--xbmc/guilib/guiinfo/SystemGUIInfo.cpp727
-rw-r--r--xbmc/guilib/guiinfo/SystemGUIInfo.h55
-rw-r--r--xbmc/guilib/guiinfo/VideoGUIInfo.cpp818
-rw-r--r--xbmc/guilib/guiinfo/VideoGUIInfo.h53
-rw-r--r--xbmc/guilib/guiinfo/VisualisationGUIInfo.cpp115
-rw-r--r--xbmc/guilib/guiinfo/VisualisationGUIInfo.h37
-rw-r--r--xbmc/guilib/guiinfo/WeatherGUIInfo.cpp81
-rw-r--r--xbmc/guilib/guiinfo/WeatherGUIInfo.h37
40 files changed, 8176 insertions, 0 deletions
diff --git a/xbmc/guilib/guiinfo/AddonsGUIInfo.cpp b/xbmc/guilib/guiinfo/AddonsGUIInfo.cpp
new file mode 100644
index 0000000..6630fa1
--- /dev/null
+++ b/xbmc/guilib/guiinfo/AddonsGUIInfo.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/AddonsGUIInfo.h"
+
+#include "FileItem.h"
+#include "ServiceBroker.h"
+#include "addons/Addon.h"
+#include "addons/AddonManager.h"
+#include "addons/addoninfo/AddonInfo.h"
+#include "guilib/LocalizeStrings.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "utils/StringUtils.h"
+
+using namespace KODI::GUILIB::GUIINFO;
+
+bool CAddonsGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ return false;
+}
+
+bool CAddonsGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ const std::shared_ptr<const ADDON::IAddon> addonInfo = item->GetAddonInfo();
+ if (addonInfo)
+ {
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case LISTITEM_ADDON_NAME:
+ value = addonInfo->Name();
+ return true;
+ case LISTITEM_ADDON_VERSION:
+ value = addonInfo->Version().asString();
+ return true;
+ case LISTITEM_ADDON_CREATOR:
+ value = addonInfo->Author();
+ return true;
+ case LISTITEM_ADDON_SUMMARY:
+ value = addonInfo->Summary();
+ return true;
+ case LISTITEM_ADDON_DESCRIPTION:
+ value = addonInfo->Description();
+ return true;
+ case LISTITEM_ADDON_DISCLAIMER:
+ value = addonInfo->Disclaimer();
+ return true;
+ case LISTITEM_ADDON_NEWS:
+ value = addonInfo->ChangeLog();
+ return true;
+ case LISTITEM_ADDON_BROKEN:
+ {
+ // Fallback for old GUI info
+ if (addonInfo->LifecycleState() == ADDON::AddonLifecycleState::BROKEN)
+ value = addonInfo->LifecycleStateDescription();
+ else
+ value = "";
+ return true;
+ }
+ case LISTITEM_ADDON_LIFECYCLE_TYPE:
+ {
+ const ADDON::AddonLifecycleState state = addonInfo->LifecycleState();
+ switch (state)
+ {
+ case ADDON::AddonLifecycleState::BROKEN:
+ value = g_localizeStrings.Get(24171); // "Broken"
+ break;
+ case ADDON::AddonLifecycleState::DEPRECATED:
+ value = g_localizeStrings.Get(24170); // "Deprecated";
+ break;
+ case ADDON::AddonLifecycleState::NORMAL:
+ default:
+ value = g_localizeStrings.Get(24169); // "Normal";
+ break;
+ }
+ return true;
+ }
+ case LISTITEM_ADDON_LIFECYCLE_DESC:
+ value = addonInfo->LifecycleStateDescription();
+ return true;
+ case LISTITEM_ADDON_TYPE:
+ value = ADDON::CAddonInfo::TranslateType(addonInfo->Type(), true);
+ return true;
+ case LISTITEM_ADDON_INSTALL_DATE:
+ value = addonInfo->InstallDate().GetAsLocalizedDateTime();
+ return true;
+ case LISTITEM_ADDON_LAST_UPDATED:
+ if (addonInfo->LastUpdated().IsValid())
+ {
+ value = addonInfo->LastUpdated().GetAsLocalizedDateTime();
+ return true;
+ }
+ break;
+ case LISTITEM_ADDON_LAST_USED:
+ if (addonInfo->LastUsed().IsValid())
+ {
+ value = addonInfo->LastUsed().GetAsLocalizedDateTime();
+ return true;
+ }
+ break;
+ case LISTITEM_ADDON_ORIGIN:
+ {
+ if (item->GetAddonInfo()->Origin() == ADDON::ORIGIN_SYSTEM)
+ {
+ value = g_localizeStrings.Get(24992);
+ return true;
+ }
+ if (!item->GetAddonInfo()->OriginName().empty())
+ {
+ value = item->GetAddonInfo()->OriginName();
+ return true;
+ }
+ else if (!item->GetAddonInfo()->Origin().empty())
+ {
+ value = item->GetAddonInfo()->Origin();
+ return true;
+ }
+ value = g_localizeStrings.Get(25014);
+ return true;
+ }
+ case LISTITEM_ADDON_SIZE:
+ {
+ uint64_t packageSize = item->GetAddonInfo()->PackageSize();
+ if (packageSize > 0)
+ {
+ value = StringUtils::FormatFileSize(packageSize);
+ return true;
+ }
+ break;
+ }
+ }
+ }
+
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ADDON_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case ADDON_SETTING_STRING:
+ {
+ ADDON::AddonPtr addon;
+ if (!CServiceBroker::GetAddonMgr().GetAddon(info.GetData3(), addon,
+ ADDON::OnlyEnabled::CHOICE_YES))
+ {
+ return false;
+ }
+ value = addon->GetSetting(info.GetData5());
+ return true;
+ }
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SYSTEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SYSTEM_ADDON_TITLE:
+ case SYSTEM_ADDON_ICON:
+ case SYSTEM_ADDON_VERSION:
+ {
+ // This logic does not check/care whether an addon has been disabled/marked as broken,
+ // it simply retrieves it's name or icon that means if an addon is placed on the home screen it
+ // will stay there even if it's disabled/marked as broken. This might need to be changed/fixed
+ // in the future.
+ ADDON::AddonPtr addon;
+ if (!info.GetData3().empty())
+ {
+ bool success = CServiceBroker::GetAddonMgr().GetAddon(info.GetData3(), addon,
+ ADDON::OnlyEnabled::CHOICE_YES);
+ if (!success || !addon)
+ break;
+
+ if (info.m_info == SYSTEM_ADDON_TITLE)
+ {
+ value = addon->Name();
+ return true;
+ }
+ if (info.m_info == SYSTEM_ADDON_ICON)
+ {
+ value = addon->Icon();
+ return true;
+ }
+ if (info.m_info == SYSTEM_ADDON_VERSION)
+ {
+ value = addon->Version().asString();
+ return true;
+ }
+ }
+ break;
+ }
+ }
+
+ return false;
+}
+
+bool CAddonsGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ADDON_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case ADDON_SETTING_INT:
+ {
+ ADDON::AddonPtr addon;
+ if (!CServiceBroker::GetAddonMgr().GetAddon(info.GetData3(), addon,
+ ADDON::OnlyEnabled::CHOICE_YES))
+ {
+ return false;
+ }
+ return addon->GetSettingInt(info.GetData5(), value);
+ }
+ }
+ return false;
+}
+
+bool CAddonsGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ADDON_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case ADDON_SETTING_BOOL:
+ {
+ ADDON::AddonPtr addon;
+ if (!CServiceBroker::GetAddonMgr().GetAddon(info.GetData3(), addon,
+ ADDON::OnlyEnabled::CHOICE_YES))
+ {
+ return false;
+ }
+ return addon->GetSettingBool(info.GetData5(), value);
+ }
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SYSTEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SYSTEM_HAS_ADDON:
+ {
+ ADDON::AddonPtr addon;
+ value = CServiceBroker::GetAddonMgr().IsAddonInstalled(info.GetData3());
+ return true;
+ }
+ case SYSTEM_ADDON_IS_ENABLED:
+ {
+ value = false;
+ ADDON::AddonPtr addon;
+ if (CServiceBroker::GetAddonMgr().GetAddon(info.GetData3(), addon,
+ ADDON::OnlyEnabled::CHOICE_YES))
+ value = !CServiceBroker::GetAddonMgr().IsAddonDisabled(info.GetData3());
+ return true;
+ }
+ case LISTITEM_ISAUTOUPDATEABLE:
+ {
+ value = true;
+ const CFileItem* item = static_cast<const CFileItem*>(gitem);
+ if (item->GetAddonInfo())
+ value = CServiceBroker::GetAddonMgr().IsAutoUpdateable(item->GetAddonInfo()->ID()) ||
+ !CServiceBroker::GetAddonMgr().IsAddonInstalled(item->GetAddonInfo()->ID(),
+ item->GetAddonInfo()->Origin());
+
+ //! @Todo: store origin of not-autoupdateable installed addons in table 'update_rules'
+ // of the addon database. this is needed to pin ambiguous addon-id's that are
+ // available from multiple origins accordingly.
+ //
+ // after this is done the above call should be changed to
+ //
+ // value = CServiceBroker::GetAddonMgr().IsAutoUpdateable(item->GetAddonInfo()->ID(),
+ // item->GetAddonInfo()->Origin());
+
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/AddonsGUIInfo.h b/xbmc/guilib/guiinfo/AddonsGUIInfo.h
new file mode 100644
index 0000000..e06ef51
--- /dev/null
+++ b/xbmc/guilib/guiinfo/AddonsGUIInfo.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CAddonsGUIInfo : public CGUIInfoProvider
+{
+public:
+ CAddonsGUIInfo() = default;
+ ~CAddonsGUIInfo() override = default;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/CMakeLists.txt b/xbmc/guilib/guiinfo/CMakeLists.txt
new file mode 100644
index 0000000..9203511
--- /dev/null
+++ b/xbmc/guilib/guiinfo/CMakeLists.txt
@@ -0,0 +1,42 @@
+set(SOURCES GUIInfo.cpp
+ GUIInfoHelper.cpp
+ GUIInfoProviders.cpp
+ GUIInfoLabel.cpp
+ GUIInfoBool.cpp
+ GUIInfoColor.cpp
+ AddonsGUIInfo.cpp
+ GamesGUIInfo.cpp
+ GUIControlsGUIInfo.cpp
+ LibraryGUIInfo.cpp
+ MusicGUIInfo.cpp
+ PicturesGUIInfo.cpp
+ PlayerGUIInfo.cpp
+ SkinGUIInfo.cpp
+ SystemGUIInfo.cpp
+ VideoGUIInfo.cpp
+ VisualisationGUIInfo.cpp
+ WeatherGUIInfo.cpp)
+
+set(HEADERS GUIInfo.h
+ GUIInfoHelper.h
+ GUIInfoLabels.h
+ GUIInfoProvider.h
+ GUIInfoProviders.h
+ GUIInfoLabel.h
+ GUIInfoBool.h
+ GUIInfoColor.h
+ IGUIInfoProvider.h
+ AddonsGUIInfo.h
+ GamesGUIInfo.h
+ GUIControlsGUIInfo.h
+ LibraryGUIInfo.h
+ MusicGUIInfo.h
+ PicturesGUIInfo.h
+ PlayerGUIInfo.h
+ SkinGUIInfo.h
+ SystemGUIInfo.h
+ VideoGUIInfo.h
+ VisualisationGUIInfo.h
+ WeatherGUIInfo.h)
+
+core_add_library(guilib_guiinfo)
diff --git a/xbmc/guilib/guiinfo/GUIControlsGUIInfo.cpp b/xbmc/guilib/guiinfo/GUIControlsGUIInfo.cpp
new file mode 100644
index 0000000..a5ee133
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIControlsGUIInfo.cpp
@@ -0,0 +1,814 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/GUIControlsGUIInfo.h"
+
+#include "FileItem.h"
+#include "ServiceBroker.h"
+#include "URL.h"
+#include "dialogs/GUIDialogKeyboardGeneric.h"
+#include "dialogs/GUIDialogNumeric.h"
+#include "dialogs/GUIDialogProgress.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIControlGroupList.h"
+#include "guilib/GUITextBox.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/IGUIContainer.h"
+#include "guilib/LocalizeStrings.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoHelper.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "music/dialogs/GUIDialogMusicInfo.h"
+#include "music/dialogs/GUIDialogSongInfo.h"
+#include "music/tags/MusicInfoTag.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+#include "video/VideoInfoTag.h"
+#include "video/dialogs/GUIDialogVideoInfo.h"
+#include "view/GUIViewState.h"
+#include "windows/GUIMediaWindow.h"
+
+using namespace KODI::GUILIB;
+using namespace KODI::GUILIB::GUIINFO;
+
+void CGUIControlsGUIInfo::SetContainerMoving(int id, bool next, bool scrolling)
+{
+ // magnitude 2 indicates a scroll, sign indicates direction
+ m_containerMoves[id] = (next ? 1 : -1) * (scrolling ? 2 : 1);
+}
+
+void CGUIControlsGUIInfo::ResetContainerMovingCache()
+{
+ m_containerMoves.clear();
+}
+
+bool CGUIControlsGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ return false;
+}
+
+bool CGUIControlsGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // CONTAINER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case CONTAINER_FOLDERPATH:
+ case CONTAINER_FOLDERNAME:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ if (info.m_info == CONTAINER_FOLDERNAME)
+ value = window->CurrentDirectory().GetLabel();
+ else
+ value = CURL(window->CurrentDirectory().GetPath()).GetWithoutUserDetails();
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_PLUGINNAME:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ const CURL url(window->CurrentDirectory().GetPath());
+ if (url.IsProtocol("plugin"))
+ {
+ value = URIUtils::GetFileName(url.GetHostName());
+ return true;
+ }
+ }
+ break;
+ }
+ case CONTAINER_VIEWCOUNT:
+ case CONTAINER_VIEWMODE:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ const CGUIControl *control = window->GetControl(window->GetViewContainerID());
+ if (control && control->IsContainer())
+ {
+ if (info.m_info == CONTAINER_VIEWMODE)
+ {
+ value = static_cast<const IGUIContainer*>(control)->GetLabel();
+ return true;
+ }
+ else if (info.m_info == CONTAINER_VIEWCOUNT)
+ {
+ value = std::to_string(window->GetViewCount());
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ case CONTAINER_SORT_METHOD:
+ case CONTAINER_SORT_ORDER:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ const CGUIViewState *viewState = window->GetViewState();
+ if (viewState)
+ {
+ if (info.m_info == CONTAINER_SORT_METHOD)
+ {
+ value = g_localizeStrings.Get(viewState->GetSortMethodLabel());
+ return true;
+ }
+ else if (info.m_info == CONTAINER_SORT_ORDER)
+ {
+ value = g_localizeStrings.Get(viewState->GetSortOrderLabel());
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ case CONTAINER_PROPERTY:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetProperty(info.GetData3()).asString();
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_ART:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetArt(info.GetData3());
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_CONTENT:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetContent();
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_SHOWPLOT:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetProperty("showplot").asString();
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_SHOWTITLE:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetProperty("showtitle").asString();
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_PLUGINCATEGORY:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetProperty("plugincategory").asString();
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_TOTALTIME:
+ case CONTAINER_TOTALWATCHED:
+ case CONTAINER_TOTALUNWATCHED:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ int count = 0;
+ const CFileItemList& items = window->CurrentDirectory();
+ for (const auto& item : items)
+ {
+ // Iterate through container and count watched, unwatched and total duration.
+ if (info.m_info == CONTAINER_TOTALWATCHED && item->HasVideoInfoTag() && item->GetVideoInfoTag()->GetPlayCount() > 0)
+ count += 1;
+ else if (info.m_info == CONTAINER_TOTALUNWATCHED && item->HasVideoInfoTag() && item->GetVideoInfoTag()->GetPlayCount() == 0)
+ count += 1;
+ else if (info.m_info == CONTAINER_TOTALTIME && item->HasMusicInfoTag())
+ count += item->GetMusicInfoTag()->GetDuration();
+ else if (info.m_info == CONTAINER_TOTALTIME && item->HasVideoInfoTag())
+ count += item->GetVideoInfoTag()->m_streamDetails.GetVideoDuration();
+ }
+ if (info.m_info == CONTAINER_TOTALTIME && count > 0)
+ {
+ value = StringUtils::SecondsToTimeString(count);
+ return true;
+ }
+ else if (info.m_info == CONTAINER_TOTALWATCHED || info.m_info == CONTAINER_TOTALUNWATCHED)
+ {
+ value = std::to_string(count);
+ return true;
+ }
+ }
+ break;
+ }
+ case CONTAINER_NUM_PAGES:
+ case CONTAINER_CURRENT_PAGE:
+ case CONTAINER_NUM_ITEMS:
+ case CONTAINER_POSITION:
+ case CONTAINER_ROW:
+ case CONTAINER_COLUMN:
+ case CONTAINER_CURRENT_ITEM:
+ case CONTAINER_NUM_ALL_ITEMS:
+ case CONTAINER_NUM_NONFOLDER_ITEMS:
+ {
+ const CGUIControl *control = nullptr;
+ if (info.GetData1())
+ { // container specified
+ CGUIWindow *window = GUIINFO::GetWindow(contextWindow);
+ if (window)
+ control = window->GetControl(info.GetData1());
+ }
+ else
+ { // no container specified - assume a mediawindow
+ CGUIMediaWindow *window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ control = window->GetControl(window->GetViewContainerID());
+ }
+ if (control)
+ {
+ if (control->IsContainer())
+ value = static_cast<const IGUIContainer*>(control)->GetLabel(info.m_info);
+ else if (control->GetControlType() == CGUIControl::GUICONTROL_GROUPLIST)
+ value = static_cast<const CGUIControlGroupList*>(control)->GetLabel(info.m_info);
+ else if (control->GetControlType() == CGUIControl::GUICONTROL_TEXTBOX)
+ value = static_cast<const CGUITextBox*>(control)->GetLabel(info.m_info);
+ return true;
+ }
+ break;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // CONTROL_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case CONTROL_GET_LABEL:
+ {
+ CGUIWindow *window = GUIINFO::GetWindow(contextWindow);
+ if (window)
+ {
+ const CGUIControl *control = window->GetControl(info.GetData1());
+ if (control)
+ {
+ int data2 = info.GetData2();
+ if (data2)
+ value = control->GetDescriptionByIndex(data2);
+ else
+ value = control->GetDescription();
+ return true;
+ }
+ }
+ break;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // WINDOW_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case WINDOW_PROPERTY:
+ {
+ CGUIWindow *window = nullptr;
+ if (info.GetData1())
+ { // window specified
+ window = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(info.GetData1());
+ }
+ else
+ { // no window specified - assume active
+ window = GUIINFO::GetWindow(contextWindow);
+ }
+ if (window)
+ {
+ value = window->GetProperty(info.GetData3()).asString();
+ return true;
+ }
+ break;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SYSTEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SYSTEM_CURRENT_WINDOW:
+ value = g_localizeStrings.Get(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog());
+ return true;
+ case SYSTEM_STARTUP_WINDOW:
+ value = std::to_string(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
+ CSettings::SETTING_LOOKANDFEEL_STARTUPWINDOW));
+ return true;
+ case SYSTEM_CURRENT_CONTROL:
+ case SYSTEM_CURRENT_CONTROL_ID:
+ {
+ CGUIWindow *window = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog());
+ if (window)
+ {
+ CGUIControl *control = window->GetFocusedControl();
+ if (control)
+ {
+ if (info.m_info == SYSTEM_CURRENT_CONTROL_ID)
+ value = std::to_string(control->GetID());
+ else if (info.m_info == SYSTEM_CURRENT_CONTROL)
+ value = control->GetDescription();
+ return true;
+ }
+ }
+ break;
+ }
+ case SYSTEM_PROGRESS_BAR:
+ {
+ CGUIDialogProgress *bar = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS);
+ if (bar && bar->IsDialogRunning())
+ value = std::to_string(bar->GetPercentage());
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // FANART_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case FANART_COLOR1:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetProperty("fanart_color1").asString();
+ return true;
+ }
+ break;
+ }
+ case FANART_COLOR2:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetProperty("fanart_color2").asString();
+ return true;
+ }
+ break;
+ }
+ case FANART_COLOR3:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetProperty("fanart_color3").asString();
+ return true;
+ }
+ break;
+ }
+ case FANART_IMAGE:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetArt("fanart");
+ return true;
+ }
+ break;
+ }
+ }
+
+ return false;
+}
+
+bool CGUIControlsGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SYSTEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SYSTEM_PROGRESS_BAR:
+ {
+ CGUIDialogProgress *bar = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS);
+ if (bar && bar->IsDialogRunning())
+ value = bar->GetPercentage();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CGUIControlsGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // CONTAINER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case CONTAINER_HASFILES:
+ case CONTAINER_HASFOLDERS:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ const CFileItemList& items = window->CurrentDirectory();
+ for (const auto& item : items)
+ {
+ if ((!item->m_bIsFolder && info.m_info == CONTAINER_HASFILES) ||
+ (item->m_bIsFolder && !item->IsParentFolder() && info.m_info == CONTAINER_HASFOLDERS))
+ {
+ value = true;
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ case CONTAINER_STACKED:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().GetProperty("isstacked").asBoolean();
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_HAS_THUMB:
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CurrentDirectory().HasArt("thumb");
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_CAN_FILTER:
+ {
+ CGUIMediaWindow *window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = !window->CanFilterAdvanced();
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_CAN_FILTERADVANCED:
+ {
+ CGUIMediaWindow *window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->CanFilterAdvanced();
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_FILTERED:
+ {
+ CGUIMediaWindow *window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = window->IsFiltered();
+ return true;
+ }
+ break;
+ }
+ case CONTAINER_SORT_METHOD:
+ {
+ CGUIMediaWindow *window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ const CGUIViewState *viewState = window->GetViewState();
+ if (viewState)
+ {
+ value = (static_cast<int>(viewState->GetSortMethod().sortBy) == info.GetData2());
+ return true;
+ }
+ }
+ break;
+ }
+ case CONTAINER_SORT_DIRECTION:
+ {
+ CGUIMediaWindow *window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ const CGUIViewState *viewState = window->GetViewState();
+ if (viewState)
+ {
+ value = (static_cast<unsigned int>(viewState->GetSortOrder()) == info.GetData1());
+ return true;
+ }
+ }
+ break;
+ }
+ case CONTAINER_CONTENT:
+ {
+ std::string content;
+ CGUIWindow *window = GUIINFO::GetWindow(contextWindow);
+ if (window)
+ {
+ if (window->GetID() == WINDOW_DIALOG_MUSIC_INFO)
+ content = static_cast<CGUIDialogMusicInfo*>(window)->GetContent();
+ else if (window->GetID() == WINDOW_DIALOG_SONG_INFO)
+ content = static_cast<CGUIDialogSongInfo*>(window)->GetContent();
+ else if (window->GetID() == WINDOW_DIALOG_VIDEO_INFO)
+ content = static_cast<CGUIDialogVideoInfo*>(window)->CurrentDirectory().GetContent();
+ }
+ if (content.empty())
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ content = window->CurrentDirectory().GetContent();
+ }
+ value = StringUtils::EqualsNoCase(info.GetData3(), content);
+ return true;
+ }
+ case CONTAINER_ROW:
+ case CONTAINER_COLUMN:
+ case CONTAINER_POSITION:
+ case CONTAINER_HAS_NEXT:
+ case CONTAINER_HAS_PREVIOUS:
+ case CONTAINER_SCROLLING:
+ case CONTAINER_SUBITEM:
+ case CONTAINER_ISUPDATING:
+ case CONTAINER_HAS_PARENT_ITEM:
+ {
+ if (info.GetData1())
+ {
+ CGUIWindow *window = GUIINFO::GetWindow(contextWindow);
+ if (window)
+ {
+ const CGUIControl *control = window->GetControl(info.GetData1());
+ if (control)
+ {
+ value = control->GetCondition(info.m_info, info.GetData2());
+ return true;
+ }
+ }
+ }
+ else
+ {
+ const CGUIControl *activeContainer = GUIINFO::GetActiveContainer(0, contextWindow);
+ if (activeContainer)
+ {
+ value = activeContainer->GetCondition(info.m_info, info.GetData2());
+ return true;
+ }
+ }
+ break;
+ }
+ case CONTAINER_HAS_FOCUS:
+ { // grab our container
+ CGUIWindow *window = GUIINFO::GetWindow(contextWindow);
+ if (window)
+ {
+ const CGUIControl *control = window->GetControl(info.GetData1());
+ if (control && control->IsContainer())
+ {
+ const CFileItemPtr item = std::static_pointer_cast<CFileItem>(static_cast<const IGUIContainer*>(control)->GetListItem(0));
+ if (item && item->m_iprogramCount == info.GetData2()) // programcount used to store item id
+ {
+ value = true;
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ case CONTAINER_SCROLL_PREVIOUS:
+ case CONTAINER_MOVE_PREVIOUS:
+ case CONTAINER_MOVE_NEXT:
+ case CONTAINER_SCROLL_NEXT:
+ {
+ int containerId = -1;
+ if (info.GetData1())
+ {
+ containerId = info.GetData1();
+ }
+ else
+ {
+ // no parameters, so we assume it's just requested for a media window. It therefore
+ // can only happen if the list has focus.
+ CGUIMediaWindow *window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ containerId = window->GetViewContainerID();
+ }
+ if (containerId != -1)
+ {
+ const std::map<int,int>::const_iterator it = m_containerMoves.find(containerId);
+ if (it != m_containerMoves.end())
+ {
+ if (info.m_info == CONTAINER_SCROLL_PREVIOUS)
+ value = it->second <= -2;
+ else if (info.m_info == CONTAINER_MOVE_PREVIOUS)
+ value = it->second <= -1;
+ else if (info.m_info == CONTAINER_MOVE_NEXT)
+ value = it->second >= 1;
+ else if (info.m_info == CONTAINER_SCROLL_NEXT)
+ value = it->second >= 2;
+ return true;
+ }
+ }
+ break;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // CONTROL_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case CONTROL_IS_VISIBLE:
+ {
+ CGUIWindow *window = GUIINFO::GetWindow(contextWindow);
+ if (window)
+ {
+ // Note: This'll only work for unique id's
+ const CGUIControl *control = window->GetControl(info.GetData1());
+ if (control)
+ {
+ value = control->IsVisible();
+ return true;
+ }
+ }
+ break;
+ }
+ case CONTROL_IS_ENABLED:
+ {
+ CGUIWindow *window = GUIINFO::GetWindow(contextWindow);
+ if (window)
+ {
+ // Note: This'll only work for unique id's
+ const CGUIControl *control = window->GetControl(info.GetData1());
+ if (control)
+ {
+ value = !control->IsDisabled();
+ return true;
+ }
+ }
+ break;
+ }
+ case CONTROL_HAS_FOCUS:
+ {
+ CGUIWindow *window = GUIINFO::GetWindow(contextWindow);
+ if (window)
+ {
+ value = (window->GetFocusedControlID() == static_cast<int>(info.GetData1()));
+ return true;
+ }
+ break;
+ }
+ case CONTROL_GROUP_HAS_FOCUS:
+ {
+ CGUIWindow *window = GUIINFO::GetWindow(contextWindow);
+ if (window)
+ {
+ value = window->ControlGroupHasFocus(info.GetData1(), info.GetData2());
+ return true;
+ }
+ break;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // WINDOW_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case WINDOW_IS_MEDIA:
+ { // note: This doesn't return true for dialogs (content, favourites, login, videoinfo)
+ CGUIWindowManager& windowMgr = CServiceBroker::GetGUI()->GetWindowManager();
+ CGUIWindow *window = windowMgr.GetWindow(windowMgr.GetActiveWindow());
+ if (window)
+ {
+ value = window->IsMediaWindow();
+ return true;
+ }
+ break;
+ }
+ case WINDOW_IS:
+ {
+ if (info.GetData1())
+ {
+ CGUIWindowManager& windowMgr = CServiceBroker::GetGUI()->GetWindowManager();
+ CGUIWindow *window = windowMgr.GetWindow(contextWindow);
+ if (!window)
+ {
+ // try topmost dialog
+ window = windowMgr.GetWindow(windowMgr.GetTopmostModalDialog());
+ if (!window)
+ {
+ // try active window
+ window = windowMgr.GetWindow(windowMgr.GetActiveWindow());
+ }
+ }
+ if (window)
+ {
+ value = (window && window->GetID() == static_cast<int>(info.GetData1()));
+ return true;
+ }
+ }
+ break;
+ }
+ case WINDOW_IS_VISIBLE:
+ {
+ if (info.GetData1())
+ value = CServiceBroker::GetGUI()->GetWindowManager().IsWindowVisible(info.GetData1());
+ else
+ value = CServiceBroker::GetGUI()->GetWindowManager().IsWindowVisible(info.GetData3());
+ return true;
+ }
+ case WINDOW_IS_ACTIVE:
+ {
+ if (info.GetData1())
+ value = CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(info.GetData1());
+ else
+ value = CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(info.GetData3());
+ return true;
+ }
+ case WINDOW_IS_DIALOG_TOPMOST:
+ {
+ if (info.GetData1())
+ value = CServiceBroker::GetGUI()->GetWindowManager().IsDialogTopmost(info.GetData1());
+ else
+ value = CServiceBroker::GetGUI()->GetWindowManager().IsDialogTopmost(info.GetData3());
+ return true;
+ }
+ case WINDOW_IS_MODAL_DIALOG_TOPMOST:
+ {
+ if (info.GetData1())
+ value = CServiceBroker::GetGUI()->GetWindowManager().IsModalDialogTopmost(info.GetData1());
+ else
+ value = CServiceBroker::GetGUI()->GetWindowManager().IsModalDialogTopmost(info.GetData3());
+ return true;
+ }
+ case WINDOW_NEXT:
+ {
+ if (info.GetData1())
+ {
+ value = (static_cast<int>(info.GetData1()) == m_nextWindowID);
+ return true;
+ }
+ else
+ {
+ CGUIWindow *window = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(m_nextWindowID);
+ if (window && StringUtils::EqualsNoCase(URIUtils::GetFileName(window->GetProperty("xmlfile").asString()), info.GetData3()))
+ {
+ value = true;
+ return true;
+ }
+ }
+ break;
+ }
+ case WINDOW_PREVIOUS:
+ {
+ if (info.GetData1())
+ {
+ value = (static_cast<int>(info.GetData1()) == m_prevWindowID);
+ return true;
+ }
+ else
+ {
+ CGUIWindow *window = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(m_prevWindowID);
+ if (window && StringUtils::EqualsNoCase(URIUtils::GetFileName(window->GetProperty("xmlfile").asString()), info.GetData3()))
+ {
+ value = true;
+ return true;
+ }
+ }
+ break;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SYSTEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SYSTEM_HAS_ACTIVE_MODAL_DIALOG:
+ value = CServiceBroker::GetGUI()->GetWindowManager().HasModalDialog(true);
+ return true;
+ case SYSTEM_HAS_VISIBLE_MODAL_DIALOG:
+ value = CServiceBroker::GetGUI()->GetWindowManager().HasVisibleModalDialog();
+ return true;
+ case SYSTEM_HAS_INPUT_HIDDEN:
+ {
+ CGUIDialogNumeric *pNumeric = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
+ CGUIDialogKeyboardGeneric *pKeyboard = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogKeyboardGeneric>(WINDOW_DIALOG_KEYBOARD);
+
+ if (pNumeric && pNumeric->IsActive())
+ value = pNumeric->IsInputHidden();
+ else if (pKeyboard && pKeyboard->IsActive())
+ value = pKeyboard->IsInputHidden();
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/GUIControlsGUIInfo.h b/xbmc/guilib/guiinfo/GUIControlsGUIInfo.h
new file mode 100644
index 0000000..f6b8b68
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIControlsGUIInfo.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/WindowIDs.h"
+#include "guilib/guiinfo/GUIInfoProvider.h"
+
+#include <map>
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CGUIControlsGUIInfo : public CGUIInfoProvider
+{
+public:
+ ~CGUIControlsGUIInfo() override = default;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+
+ void SetNextWindow(int windowID) { m_nextWindowID = windowID; }
+ void SetPreviousWindow(int windowID) { m_prevWindowID = windowID; }
+
+ /*! \brief containers call this to specify that the focus is changing
+ \param id control id
+ \param next true if we're moving to the next item, false if previous
+ \param scrolling true if the container is scrolling, false if the movement requires no scroll
+ */
+ void SetContainerMoving(int id, bool next, bool scrolling);
+ void ResetContainerMovingCache();
+
+private:
+ int m_nextWindowID = WINDOW_INVALID;
+ int m_prevWindowID = WINDOW_INVALID;
+
+ std::map<int, int> m_containerMoves; // direction of list moving
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/GUIInfo.cpp b/xbmc/guilib/guiinfo/GUIInfo.cpp
new file mode 100644
index 0000000..5542a78
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfo.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "GUIInfo.h"
+
+#include <assert.h>
+
+using namespace KODI::GUILIB::GUIINFO;
+
+void CGUIInfo::SetInfoFlag(uint32_t flag)
+{
+ assert(flag >= (1 << 24));
+ m_data1 |= flag;
+}
+
+uint32_t CGUIInfo::GetInfoFlag() const
+{
+ // we strip out the bottom 24 bits, where we keep data
+ // and return the flag only
+ return m_data1 & 0xff000000;
+}
+
+uint32_t CGUIInfo::GetData1() const
+{
+ // we strip out the top 8 bits, where we keep flags
+ // and return the unflagged data
+ return m_data1 & ((1 << 24) -1);
+}
diff --git a/xbmc/guilib/guiinfo/GUIInfo.h b/xbmc/guilib/guiinfo/GUIInfo.h
new file mode 100644
index 0000000..c5bffe8
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfo.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <string>
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+// class to hold multiple integer data
+// for storage referenced from a single integer
+class CGUIInfo
+{
+public:
+ CGUIInfo(int info, uint32_t data1, int data2, uint32_t flag, const std::string& data3, int data4)
+ : m_info(info),
+ m_data1(data1),
+ m_data2(data2),
+ m_data3(data3),
+ m_data4(data4)
+ {
+ if (flag)
+ SetInfoFlag(flag);
+ }
+
+ explicit CGUIInfo(int info, uint32_t data1 = 0, int data2 = 0, uint32_t flag = 0)
+ : m_info(info),
+ m_data1(data1),
+ m_data2(data2),
+ m_data4(0)
+ {
+ if (flag)
+ SetInfoFlag(flag);
+ }
+
+ CGUIInfo(int info, uint32_t data1, int data2, const std::string& data3)
+ : m_info(info), m_data1(data1), m_data2(data2), m_data3(data3), m_data4(0)
+ {
+ }
+
+ CGUIInfo(int info, uint32_t data1, const std::string& data3)
+ : m_info(info),
+ m_data1(data1),
+ m_data2(0),
+ m_data3(data3),
+ m_data4(0)
+ {
+ }
+
+ CGUIInfo(int info, const std::string& data3)
+ : m_info(info),
+ m_data1(0),
+ m_data2(0),
+ m_data3(data3),
+ m_data4(0)
+ {
+ }
+
+ CGUIInfo(int info, const std::string& data3, int data2)
+ : m_info(info),
+ m_data1(0),
+ m_data2(data2),
+ m_data3(data3),
+ m_data4(0)
+ {
+ }
+
+ CGUIInfo(int info, const std::string& data3, const std::string& data5)
+ : m_info(info), m_data1(0), m_data3(data3), m_data4(0), m_data5(data5)
+ {
+ }
+
+ bool operator ==(const CGUIInfo &right) const
+ {
+ return (m_info == right.m_info && m_data1 == right.m_data1 && m_data2 == right.m_data2 &&
+ m_data3 == right.m_data3 && m_data4 == right.m_data4 && m_data5 == right.m_data5);
+ }
+
+ uint32_t GetInfoFlag() const;
+ uint32_t GetData1() const;
+ int GetData2() const { return m_data2; }
+ const std::string& GetData3() const { return m_data3; }
+ int GetData4() const { return m_data4; }
+ const std::string& GetData5() const { return m_data5; }
+
+ int m_info;
+private:
+ void SetInfoFlag(uint32_t flag);
+
+ uint32_t m_data1;
+ int m_data2;
+ std::string m_data3;
+ int m_data4;
+ std::string m_data5;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/GUIInfoBool.cpp b/xbmc/guilib/guiinfo/GUIInfoBool.cpp
new file mode 100644
index 0000000..2f6b4f9
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoBool.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/GUIInfoBool.h"
+
+#include "GUIInfoManager.h"
+#include "ServiceBroker.h"
+#include "guilib/GUIComponent.h"
+
+using namespace KODI::GUILIB::GUIINFO;
+
+CGUIInfoBool::CGUIInfoBool(bool value)
+{
+ m_value = value;
+}
+
+CGUIInfoBool::~CGUIInfoBool() = default;
+
+void CGUIInfoBool::Parse(const std::string &expression, int context)
+{
+ if (expression == "true")
+ m_value = true;
+ else if (expression == "false")
+ m_value = false;
+ else
+ {
+ m_info = CServiceBroker::GetGUI()->GetInfoManager().Register(expression, context);
+ Update(context);
+ }
+}
+
+void CGUIInfoBool::Update(int contextWindow, const CGUIListItem* item /*= nullptr*/)
+{
+ if (m_info)
+ m_value = m_info->Get(contextWindow, item);
+}
diff --git a/xbmc/guilib/guiinfo/GUIInfoBool.h b/xbmc/guilib/guiinfo/GUIInfoBool.h
new file mode 100644
index 0000000..1913684
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoBool.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+/*!
+\file GUIInfoBool.h
+\brief
+*/
+
+#include "interfaces/info/InfoBool.h"
+
+#include <string>
+
+class CGUIListItem;
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfoBool
+{
+public:
+ explicit CGUIInfoBool(bool value = false);
+ ~CGUIInfoBool();
+
+ operator bool() const { return m_value; }
+
+ void Update(int contextWindow, const CGUIListItem* item = nullptr);
+ void Parse(const std::string &expression, int context);
+private:
+ INFO::InfoPtr m_info;
+ bool m_value;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/GUIInfoColor.cpp b/xbmc/guilib/guiinfo/GUIInfoColor.cpp
new file mode 100644
index 0000000..c20326d
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoColor.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/GUIInfoColor.h"
+
+#include "FileItem.h"
+#include "GUIInfoManager.h"
+#include "ServiceBroker.h"
+#include "addons/Skin.h"
+#include "guilib/GUIColorManager.h"
+#include "guilib/GUIComponent.h"
+#include "utils/StringUtils.h"
+
+using namespace KODI::GUILIB::GUIINFO;
+
+bool CGUIInfoColor::Update(const CGUIListItem* item /* = nullptr */)
+{
+ if (!m_info)
+ return false; // no infolabel
+
+ // Expand the infolabel, and then convert it to a color
+ std::string infoLabel;
+ if (item && item->IsFileItem())
+ infoLabel = CServiceBroker::GetGUI()->GetInfoManager().GetItemLabel(
+ static_cast<const CFileItem*>(item), 0, m_info);
+ else
+ infoLabel = CServiceBroker::GetGUI()->GetInfoManager().GetLabel(m_info, INFO::DEFAULT_CONTEXT);
+
+ UTILS::COLOR::Color color =
+ !infoLabel.empty() ? CServiceBroker::GetGUI()->GetColorManager().GetColor(infoLabel) : 0;
+ if (m_color != color)
+ {
+ m_color = color;
+ return true;
+ }
+ else
+ return false;
+}
+
+void CGUIInfoColor::Parse(const std::string &label, int context)
+{
+ if (label.empty())
+ return;
+
+ CGUIInfoManager& infoMgr = CServiceBroker::GetGUI()->GetInfoManager();
+
+ // Check for the standard $INFO[] block layout, and strip it if present
+ std::string label2 = label;
+ if (StringUtils::StartsWithNoCase(label, "$var["))
+ {
+ label2 = label.substr(5, label.length() - 6);
+ m_info = infoMgr.TranslateSkinVariableString(label2, context);
+ if (!m_info)
+ m_info = infoMgr.RegisterSkinVariableString(g_SkinInfo->CreateSkinVariable(label2, context));
+ return;
+ }
+
+ if (StringUtils::StartsWithNoCase(label, "$info["))
+ label2 = label.substr(6, label.length()-7);
+
+ m_info = infoMgr.TranslateString(label2);
+ if (!m_info)
+ m_color = CServiceBroker::GetGUI()->GetColorManager().GetColor(label);
+}
diff --git a/xbmc/guilib/guiinfo/GUIInfoColor.h b/xbmc/guilib/guiinfo/GUIInfoColor.h
new file mode 100644
index 0000000..a711047
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoColor.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+/*!
+\file GUIInfoColor.h
+\brief
+*/
+
+#include "guilib/GUIListItem.h"
+#include "utils/ColorUtils.h"
+
+#include <string>
+
+class CGUIListItem;
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfoColor
+{
+public:
+ constexpr CGUIInfoColor(UTILS::COLOR::Color color = 0) : m_color(color) {}
+
+ constexpr operator UTILS::COLOR::Color() const { return m_color; }
+
+ bool Update(const CGUIListItem* item = nullptr);
+ void Parse(const std::string &label, int context);
+
+ /*!
+ * @brief Check if the infocolor has an info condition bound to its color definition (or otherwise, if it's constant color)
+ * @return true if the color depends on an info condition, false otherwise
+ */
+ bool HasInfo() const { return m_info != 0; }
+
+private:
+ int m_info = 0;
+ UTILS::COLOR::Color m_color;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/GUIInfoHelper.cpp b/xbmc/guilib/guiinfo/GUIInfoHelper.cpp
new file mode 100644
index 0000000..f025b5e
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoHelper.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "GUIInfoHelper.h"
+
+#include "FileItem.h"
+#include "PlayListPlayer.h"
+#include "ServiceBroker.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindow.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/IGUIContainer.h"
+#include "guilib/LocalizeStrings.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "playlists/PlayList.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+#include "windows/GUIMediaWindow.h"
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+// conditions for window retrieval
+static const int WINDOW_CONDITION_HAS_LIST_ITEMS = 1;
+static const int WINDOW_CONDITION_IS_MEDIA_WINDOW = 2;
+
+std::string GetPlaylistLabel(int item, PLAYLIST::Id playlistId /* = TYPE_NONE */)
+{
+ PLAYLIST::CPlayListPlayer& player = CServiceBroker::GetPlaylistPlayer();
+
+ if (playlistId == PLAYLIST::TYPE_NONE)
+ playlistId = player.GetCurrentPlaylist();
+
+ switch (item)
+ {
+ case PLAYLIST_LENGTH:
+ {
+ return std::to_string(player.GetPlaylist(playlistId).size());
+ }
+ case PLAYLIST_POSITION:
+ {
+ int currentSong = player.GetCurrentSong();
+ if (currentSong > -1)
+ return std::to_string(currentSong + 1);
+ break;
+ }
+ case PLAYLIST_RANDOM:
+ {
+ if (player.IsShuffled(playlistId))
+ return g_localizeStrings.Get(16041); // 16041: On
+ else
+ return g_localizeStrings.Get(591); // 591: Off
+ }
+ case PLAYLIST_REPEAT:
+ {
+ PLAYLIST::RepeatState state = player.GetRepeat(playlistId);
+ if (state == PLAYLIST::RepeatState::ONE)
+ return g_localizeStrings.Get(592); // 592: One
+ else if (state == PLAYLIST::RepeatState::ALL)
+ return g_localizeStrings.Get(593); // 593: All
+ else
+ return g_localizeStrings.Get(594); // 594: Off
+ }
+ }
+ return std::string();
+}
+
+namespace
+{
+
+bool CheckWindowCondition(CGUIWindow *window, int condition)
+{
+ // check if it satisfies our condition
+ if (!window)
+ return false;
+ if ((condition & WINDOW_CONDITION_HAS_LIST_ITEMS) && !window->HasListItems())
+ return false;
+ if ((condition & WINDOW_CONDITION_IS_MEDIA_WINDOW) && !window->IsMediaWindow())
+ return false;
+ return true;
+}
+
+CGUIWindow* GetWindowWithCondition(int contextWindow, int condition)
+{
+ const CGUIWindowManager& windowMgr = CServiceBroker::GetGUI()->GetWindowManager();
+
+ CGUIWindow *window = windowMgr.GetWindow(contextWindow);
+ if (CheckWindowCondition(window, condition))
+ return window;
+
+ // try topmost dialog
+ window = windowMgr.GetWindow(windowMgr.GetTopmostModalDialog());
+ if (CheckWindowCondition(window, condition))
+ return window;
+
+ // try active window
+ window = windowMgr.GetWindow(windowMgr.GetActiveWindow());
+ if (CheckWindowCondition(window, condition))
+ return window;
+
+ return nullptr;
+}
+
+} // unnamed namespace
+
+CGUIWindow* GetWindow(int contextWindow)
+{
+ return GetWindowWithCondition(contextWindow, 0);
+}
+
+CFileItemPtr GetCurrentListItemFromWindow(int contextWindow)
+{
+ CGUIWindow* window = GetWindowWithCondition(contextWindow, WINDOW_CONDITION_HAS_LIST_ITEMS);
+ if (window)
+ return window->GetCurrentListItem();
+
+ return CFileItemPtr();
+}
+
+CGUIMediaWindow* GetMediaWindow(int contextWindow)
+{
+ CGUIWindow* window = GetWindowWithCondition(contextWindow, WINDOW_CONDITION_IS_MEDIA_WINDOW);
+ if (window)
+ return static_cast<CGUIMediaWindow*>(window);
+
+ return nullptr;
+}
+
+CGUIControl* GetActiveContainer(int containerId, int contextWindow)
+{
+ CGUIWindow *window = GetWindow(contextWindow);
+ if (!window)
+ return nullptr;
+
+ CGUIControl *control = nullptr;
+ if (!containerId) // No container specified, so we lookup the current view container
+ {
+ if (window->IsMediaWindow())
+ containerId = static_cast<CGUIMediaWindow*>(window)->GetViewContainerID();
+ else
+ control = window->GetFocusedControl();
+ }
+
+ if (!control)
+ control = window->GetControl(containerId);
+
+ if (control && control->IsContainer())
+ return control;
+
+ return nullptr;
+}
+
+CGUIListItemPtr GetCurrentListItem(int contextWindow, int containerId /* = 0 */, int itemOffset /* = 0 */, unsigned int itemFlags /* = 0 */)
+{
+ CGUIListItemPtr item;
+
+ if (containerId == 0 &&
+ itemOffset == 0 &&
+ !(itemFlags & INFOFLAG_LISTITEM_CONTAINER) &&
+ !(itemFlags & INFOFLAG_LISTITEM_ABSOLUTE) &&
+ !(itemFlags & INFOFLAG_LISTITEM_POSITION))
+ item = GetCurrentListItemFromWindow(contextWindow);
+
+ if (!item)
+ {
+ CGUIControl* activeContainer = GetActiveContainer(containerId, contextWindow);
+ if (activeContainer)
+ item = static_cast<IGUIContainer *>(activeContainer)->GetListItem(itemOffset, itemFlags);
+ }
+
+ return item;
+}
+
+std::string GetFileInfoLabelValueFromPath(int info, const std::string& filenameAndPath)
+{
+ std::string value = filenameAndPath;
+
+ if (info == PLAYER_PATH)
+ {
+ // do this twice since we want the path outside the archive if this is to be of use.
+ if (URIUtils::IsInArchive(value))
+ value = URIUtils::GetParentPath(value);
+
+ value = URIUtils::GetParentPath(value);
+ }
+ else if (info == PLAYER_FILENAME)
+ {
+ value = URIUtils::GetFileName(value);
+ }
+
+ return value;
+}
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/GUIInfoHelper.h b/xbmc/guilib/guiinfo/GUIInfoHelper.h
new file mode 100644
index 0000000..ce5191e
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoHelper.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "playlists/PlayListTypes.h"
+
+#include <memory>
+#include <string>
+
+class CFileItem;
+
+class CGUIListItem;
+typedef std::shared_ptr<CGUIListItem> CGUIListItemPtr;
+
+class CGUIControl;
+class CGUIMediaWindow;
+class CGUIWindow;
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+std::string GetPlaylistLabel(int item, PLAYLIST::Id playlistid = PLAYLIST::TYPE_NONE);
+
+CGUIWindow* GetWindow(int contextWindow);
+CGUIControl* GetActiveContainer(int containerId, int contextWindow);
+CGUIMediaWindow* GetMediaWindow(int contextWindow);
+CGUIListItemPtr GetCurrentListItem(int contextWindow, int containerId = 0, int itemOffset = 0, unsigned int itemFlags = 0);
+
+std::string GetFileInfoLabelValueFromPath(int info, const std::string& filenameAndPath);
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/GUIInfoLabel.cpp b/xbmc/guilib/guiinfo/GUIInfoLabel.cpp
new file mode 100644
index 0000000..4a6ce13
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoLabel.cpp
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/GUIInfoLabel.h"
+
+#include "FileItem.h"
+#include "GUIInfoManager.h"
+#include "addons/Skin.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIListItem.h"
+#include "guilib/LocalizeStrings.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+using namespace KODI::GUILIB::GUIINFO;
+
+CGUIInfoLabel::CGUIInfoLabel(const std::string &label, const std::string &fallback /*= ""*/, int context /*= 0*/)
+{
+ SetLabel(label, fallback, context);
+}
+
+int CGUIInfoLabel::GetIntValue(int contextWindow) const
+{
+ const std::string label = GetLabel(contextWindow);
+ if (!label.empty())
+ return strtol(label.c_str(), NULL, 10);
+
+ return 0;
+}
+
+void CGUIInfoLabel::SetLabel(const std::string &label, const std::string &fallback, int context /*= 0*/)
+{
+ m_fallback = fallback;
+ Parse(label, context);
+}
+
+const std::string &CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage, std::string *fallback /*= NULL*/) const
+{
+ bool needsUpdate = m_dirty;
+ if (!m_info.empty())
+ {
+ CGUIInfoManager& infoMgr = CServiceBroker::GetGUI()->GetInfoManager();
+ for (const auto &portion : m_info)
+ {
+ if (portion.m_info)
+ {
+ std::string infoLabel;
+ if (preferImage)
+ infoLabel = infoMgr.GetImage(portion.m_info, contextWindow, fallback);
+ if (infoLabel.empty())
+ infoLabel = infoMgr.GetLabel(portion.m_info, contextWindow, fallback);
+ needsUpdate |= portion.NeedsUpdate(infoLabel);
+ }
+ }
+ }
+ else
+ needsUpdate = !m_label.empty();
+
+ return CacheLabel(needsUpdate);
+}
+
+const std::string &CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImages, std::string *fallback /*= NULL*/) const
+{
+ bool needsUpdate = m_dirty;
+ if (item->IsFileItem() && !m_info.empty())
+ {
+ CGUIInfoManager& infoMgr = CServiceBroker::GetGUI()->GetInfoManager();
+ for (const auto &portion : m_info)
+ {
+ if (portion.m_info)
+ {
+ std::string infoLabel;
+ if (preferImages)
+ infoLabel = infoMgr.GetItemImage(item, 0, portion.m_info, fallback);
+ else
+ infoLabel = infoMgr.GetItemLabel(static_cast<const CFileItem *>(item), 0, portion.m_info, fallback);
+ needsUpdate |= portion.NeedsUpdate(infoLabel);
+ }
+ }
+ }
+ else
+ needsUpdate = !m_label.empty();
+
+ return CacheLabel(needsUpdate);
+}
+
+const std::string &CGUIInfoLabel::CacheLabel(bool rebuild) const
+{
+ if (rebuild)
+ {
+ m_label.clear();
+ for (const auto &portion : m_info)
+ m_label += portion.Get();
+ m_dirty = false;
+ }
+ if (m_label.empty()) // empty label, use the fallback
+ return m_fallback;
+ return m_label;
+}
+
+bool CGUIInfoLabel::IsEmpty() const
+{
+ return m_info.empty();
+}
+
+bool CGUIInfoLabel::IsConstant() const
+{
+ return m_info.empty() || (m_info.size() == 1 && m_info[0].m_info == 0);
+}
+
+bool CGUIInfoLabel::ReplaceSpecialKeywordReferences(const std::string &strInput, const std::string &strKeyword, const StringReplacerFunc &func, std::string &strOutput)
+{
+ // replace all $strKeyword[value] with resolved strings
+ const std::string dollarStrPrefix = "$" + strKeyword + "[";
+
+ size_t index = 0;
+ size_t startPos;
+
+ while ((startPos = strInput.find(dollarStrPrefix, index)) != std::string::npos)
+ {
+ size_t valuePos = startPos + dollarStrPrefix.size();
+ size_t endPos = StringUtils::FindEndBracket(strInput, '[', ']', valuePos);
+ if (endPos != std::string::npos)
+ {
+ if (index == 0) // first occurrence?
+ strOutput.clear();
+ strOutput.append(strInput, index, startPos - index); // append part from the left side
+ strOutput += func(strInput.substr(valuePos, endPos - valuePos)); // resolve and append value part
+ index = endPos + 1;
+ }
+ else
+ {
+ // if closing bracket is missing, report error and leave incomplete reference in
+ CLog::Log(LOGERROR, "Error parsing value - missing ']' in \"{}\"", strInput);
+ break;
+ }
+ }
+
+ if (index) // if we replaced anything
+ {
+ strOutput.append(strInput, index, std::string::npos); // append leftover from the right side
+ return true;
+ }
+
+ return false;
+}
+
+bool CGUIInfoLabel::ReplaceSpecialKeywordReferences(std::string &work, const std::string &strKeyword, const StringReplacerFunc &func)
+{
+ std::string output;
+ if (ReplaceSpecialKeywordReferences(work, strKeyword, func, output))
+ {
+ work = std::move(output);
+ return true;
+ }
+ return false;
+}
+
+std::string LocalizeReplacer(const std::string &str)
+{
+ std::string replace = g_localizeStringsTemp.Get(atoi(str.c_str()));
+ if (replace.empty())
+ replace = g_localizeStrings.Get(atoi(str.c_str()));
+ return replace;
+}
+
+std::string AddonReplacer(const std::string &str)
+{
+ // assumes "addon.id #####"
+ size_t length = str.find(' ');
+ const std::string addonid = str.substr(0, length);
+ int stringid = atoi(str.substr(length + 1).c_str());
+ return g_localizeStrings.GetAddonString(addonid, stringid);
+}
+
+std::string NumberReplacer(const std::string &str)
+{
+ return str;
+}
+
+std::string CGUIInfoLabel::ReplaceLocalize(const std::string &label)
+{
+ std::string work(label);
+ ReplaceSpecialKeywordReferences(work, "LOCALIZE", LocalizeReplacer);
+ ReplaceSpecialKeywordReferences(work, "NUMBER", NumberReplacer);
+ return work;
+}
+
+std::string CGUIInfoLabel::ReplaceAddonStrings(std::string &&label)
+{
+ ReplaceSpecialKeywordReferences(label, "ADDON", AddonReplacer);
+ return std::move(label);
+}
+
+enum EINFOFORMAT { NONE = 0, FORMATINFO, FORMATESCINFO, FORMATVAR, FORMATESCVAR };
+
+typedef struct
+{
+ const char *str;
+ EINFOFORMAT val;
+} infoformat;
+
+const static infoformat infoformatmap[] = {{ "$INFO[", FORMATINFO},
+ { "$ESCINFO[", FORMATESCINFO},
+ { "$VAR[", FORMATVAR},
+ { "$ESCVAR[", FORMATESCVAR}};
+
+void CGUIInfoLabel::Parse(const std::string &label, int context)
+{
+ m_info.clear();
+ m_dirty = true;
+ // Step 1: Replace all $LOCALIZE[number] with the real string
+ std::string work = ReplaceLocalize(label);
+ // Step 2: Replace all $ADDON[id number] with the real string
+ work = ReplaceAddonStrings(std::move(work));
+ // Step 3: Find all $INFO[info,prefix,postfix] blocks
+ EINFOFORMAT format;
+ do
+ {
+ format = NONE;
+ size_t pos1 = work.size();
+ size_t pos2;
+ size_t len = 0;
+ for (const infoformat& infoformat : infoformatmap)
+ {
+ pos2 = work.find(infoformat.str);
+ if (pos2 != std::string::npos && pos2 < pos1)
+ {
+ pos1 = pos2;
+ len = strlen(infoformat.str);
+ format = infoformat.val;
+ }
+ }
+
+ if (format != NONE)
+ {
+ if (pos1 > 0)
+ m_info.emplace_back(0, work.substr(0, pos1), "");
+
+ pos2 = StringUtils::FindEndBracket(work, '[', ']', pos1 + len);
+ if (pos2 != std::string::npos)
+ {
+ // decipher the block
+ std::vector<std::string> params = StringUtils::Split(work.substr(pos1 + len, pos2 - pos1 - len), ",");
+ if (!params.empty())
+ {
+ CGUIInfoManager& infoMgr = CServiceBroker::GetGUI()->GetInfoManager();
+
+ int info;
+ if (format == FORMATVAR || format == FORMATESCVAR)
+ {
+ info = infoMgr.TranslateSkinVariableString(params[0], context);
+ if (info == 0)
+ info = infoMgr.RegisterSkinVariableString(g_SkinInfo->CreateSkinVariable(params[0], context));
+ if (info == 0) // skinner didn't define this conditional label!
+ CLog::Log(LOGWARNING, "Label Formatting: $VAR[{}] is not defined", params[0]);
+ }
+ else
+ info = infoMgr.TranslateString(params[0]);
+ std::string prefix, postfix;
+ if (params.size() > 1)
+ prefix = params[1];
+ if (params.size() > 2)
+ postfix = params[2];
+ m_info.emplace_back(info, prefix, postfix, format == FORMATESCINFO || format == FORMATESCVAR);
+ }
+ // and delete it from our work string
+ work.erase(0, pos2 + 1);
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "Error parsing label - missing ']' in \"{}\"", label);
+ return;
+ }
+ }
+ }
+ while (format != NONE);
+
+ if (!work.empty())
+ m_info.emplace_back(0, work, "");
+}
+
+CGUIInfoLabel::CInfoPortion::CInfoPortion(int info, const std::string &prefix, const std::string &postfix, bool escaped /*= false */):
+ m_prefix(prefix),
+ m_postfix(postfix)
+{
+ m_info = info;
+ m_escaped = escaped;
+ // filter our prefix and postfix for comma's
+ StringUtils::Replace(m_prefix, "$COMMA", ",");
+ StringUtils::Replace(m_postfix, "$COMMA", ",");
+ StringUtils::Replace(m_prefix, "$LBRACKET", "["); StringUtils::Replace(m_prefix, "$RBRACKET", "]");
+ StringUtils::Replace(m_postfix, "$LBRACKET", "["); StringUtils::Replace(m_postfix, "$RBRACKET", "]");
+}
+
+bool CGUIInfoLabel::CInfoPortion::NeedsUpdate(const std::string &label) const
+{
+ if (m_label != label)
+ {
+ m_label = label;
+ return true;
+ }
+ return false;
+}
+
+std::string CGUIInfoLabel::CInfoPortion::Get() const
+{
+ if (!m_info)
+ return m_prefix;
+ else if (m_label.empty())
+ return "";
+ std::string label = m_prefix + m_label + m_postfix;
+ if (m_escaped) // escape all quotes and backslashes, then quote
+ {
+ StringUtils::Replace(label, "\\", "\\\\");
+ StringUtils::Replace(label, "\"", "\\\"");
+ return "\"" + label + "\"";
+ }
+ return label;
+}
+
+std::string CGUIInfoLabel::GetLabel(const std::string &label, int contextWindow /*= 0*/, bool preferImage /*= false */)
+{ // translate the label
+ const CGUIInfoLabel info(label, "", contextWindow);
+ return info.GetLabel(contextWindow, preferImage);
+}
+
+std::string CGUIInfoLabel::GetItemLabel(const std::string &label, const CGUIListItem *item, bool preferImage /*= false */)
+{ // translate the label
+ const CGUIInfoLabel info(label);
+ return info.GetItemLabel(item, preferImage);
+}
diff --git a/xbmc/guilib/guiinfo/GUIInfoLabel.h b/xbmc/guilib/guiinfo/GUIInfoLabel.h
new file mode 100644
index 0000000..c9ae1a8
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoLabel.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+/*!
+\file GUIInfoLabel.h
+\brief
+*/
+
+#include "interfaces/info/Info.h"
+
+#include <functional>
+#include <string>
+#include <vector>
+
+class CGUIListItem;
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfoLabel
+{
+public:
+ CGUIInfoLabel() = default;
+ CGUIInfoLabel(const std::string& label,
+ const std::string& fallback = "",
+ int context = INFO::DEFAULT_CONTEXT);
+
+ void SetLabel(const std::string& label,
+ const std::string& fallback,
+ int context = INFO::DEFAULT_CONTEXT);
+
+ /*!
+ \brief Gets a label (or image) for a given window context from the info manager.
+ \param contextWindow the context in which to evaluate the expression.
+ \param preferImage caller is specifically wanting an image rather than a label. Defaults to false.
+ \param fallback if non-NULL, is set to an alternate value to use should the actual value be not appropriate. Defaults to NULL.
+ \return label (or image).
+ */
+ const std::string &GetLabel(int contextWindow, bool preferImage = false, std::string *fallback = NULL) const;
+
+ /*!
+ \brief Gets the label and returns it as an int value
+ \param contextWindow the context in which to evaluate the expression.
+ \return int value.
+ \sa GetLabel
+ */
+ int GetIntValue(int contextWindow) const;
+
+ /*!
+ \brief Gets a label (or image) for a given listitem from the info manager.
+ \param item listitem in question.
+ \param preferImage caller is specifically wanting an image rather than a label. Defaults to false.
+ \param fallback if non-NULL, is set to an alternate value to use should the actual value be not appropriate. Defaults to NULL.
+ \return label (or image).
+ */
+ const std::string &GetItemLabel(const CGUIListItem *item, bool preferImage = false, std::string *fallback = NULL) const;
+
+ bool IsConstant() const;
+ bool IsEmpty() const;
+
+ const std::string& GetFallback() const { return m_fallback; }
+
+ static std::string GetLabel(const std::string& label,
+ int contextWindow,
+ bool preferImage = false);
+ static std::string GetItemLabel(const std::string &label, const CGUIListItem *item, bool preferImage = false);
+
+ /*!
+ \brief Replaces instances of $LOCALIZE[number] with the appropriate localized string
+ \param label text to replace
+ \return text with any localized strings filled in.
+ */
+ static std::string ReplaceLocalize(const std::string &label);
+
+ /*!
+ \brief Replaces instances of $ADDON[id number] with the appropriate localized addon string
+ \param label text to replace
+ \return text with any localized strings filled in.
+ */
+ static std::string ReplaceAddonStrings(std::string &&label);
+
+ typedef std::function<std::string(const std::string&)> StringReplacerFunc;
+
+ /*!
+ \brief Replaces instances of $strKeyword[value] with the appropriate resolved string
+ \param strInput text to replace
+ \param strKeyword keyword to look for
+ \param func function that does the actual replacement of each bracketed value found
+ \param strOutput the output string
+ \return whether anything has been replaced.
+ */
+ static bool ReplaceSpecialKeywordReferences(const std::string &strInput, const std::string &strKeyword, const StringReplacerFunc &func, std::string &strOutput);
+
+ /*!
+ \brief Replaces instances of $strKeyword[value] with the appropriate resolved string in-place
+ \param work text to replace in-place
+ \param strKeyword keyword to look for
+ \param func function that does the actual replacement of each bracketed value found
+ \return whether anything has been replaced.
+ */
+ static bool ReplaceSpecialKeywordReferences(std::string &work, const std::string &strKeyword, const StringReplacerFunc &func);
+
+private:
+ void Parse(const std::string &label, int context);
+
+ /*! \brief return (and cache) built label from info portions.
+ \param rebuild whether we need to rebuild the label
+ \sa GetLabel, GetItemLabel
+ */
+ const std::string &CacheLabel(bool rebuild) const;
+
+ class CInfoPortion
+ {
+ public:
+ CInfoPortion(int info, const std::string &prefix, const std::string &postfix, bool escaped = false);
+ bool NeedsUpdate(const std::string &label) const;
+ std::string Get() const;
+ int m_info;
+ private:
+ bool m_escaped;
+ mutable std::string m_label;
+ std::string m_prefix;
+ std::string m_postfix;
+ };
+
+ mutable bool m_dirty = false;
+ mutable std::string m_label;
+ std::string m_fallback;
+ std::vector<CInfoPortion> m_info;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
+
diff --git a/xbmc/guilib/guiinfo/GUIInfoLabels.h b/xbmc/guilib/guiinfo/GUIInfoLabels.h
new file mode 100644
index 0000000..3e2b163
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoLabels.h
@@ -0,0 +1,985 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+// clang-format off
+#define PLAYER_HAS_MEDIA 1
+#define PLAYER_HAS_AUDIO 2
+#define PLAYER_HAS_VIDEO 3
+#define PLAYER_PLAYING 4
+#define PLAYER_PAUSED 5
+#define PLAYER_REWINDING 6
+#define PLAYER_REWINDING_2x 7
+#define PLAYER_REWINDING_4x 8
+#define PLAYER_REWINDING_8x 9
+#define PLAYER_REWINDING_16x 10
+#define PLAYER_REWINDING_32x 11
+#define PLAYER_FORWARDING 12
+#define PLAYER_FORWARDING_2x 13
+#define PLAYER_FORWARDING_4x 14
+#define PLAYER_FORWARDING_8x 15
+#define PLAYER_FORWARDING_16x 16
+#define PLAYER_FORWARDING_32x 17
+#define PLAYER_CACHING 20
+// unused id 21
+#define PLAYER_PROGRESS 22
+#define PLAYER_SEEKBAR 23
+#define PLAYER_SEEKTIME 24
+#define PLAYER_SEEKING 25
+#define PLAYER_SHOWTIME 26
+#define PLAYER_TIME 27
+#define PLAYER_TIME_REMAINING 28
+#define PLAYER_DURATION 29
+#define PLAYER_HASPERFORMEDSEEK 30
+#define PLAYER_SHOWINFO 31
+#define PLAYER_VOLUME 32
+#define PLAYER_MUTED 33
+#define PLAYER_HASDURATION 34
+#define PLAYER_CHAPTER 35
+#define PLAYER_CHAPTERCOUNT 36
+#define PLAYER_TIME_SPEED 37
+#define PLAYER_FINISH_TIME 38
+#define PLAYER_CACHELEVEL 39
+#define PLAYER_CHAPTERNAME 41
+#define PLAYER_SUBTITLE_DELAY 42
+#define PLAYER_AUDIO_DELAY 43
+#define PLAYER_PASSTHROUGH 44
+// unused 45
+// unused 46
+#define PLAYER_SEEKOFFSET 47
+#define PLAYER_PROGRESS_CACHE 48
+#define PLAYER_ITEM_ART 49
+#define PLAYER_CAN_PAUSE 50
+#define PLAYER_CAN_SEEK 51
+#define PLAYER_START_TIME 52
+// unused 53
+#define PLAYER_ISINTERNETSTREAM 54
+// unused 55
+#define PLAYER_SEEKSTEPSIZE 56
+#define PLAYER_IS_CHANNEL_PREVIEW_ACTIVE 57
+#define PLAYER_SUPPORTS_TEMPO 58
+#define PLAYER_IS_TEMPO 59
+#define PLAYER_PLAYSPEED 60
+#define PLAYER_SEEKNUMERIC 61
+#define PLAYER_HAS_GAME 62
+#define PLAYER_HAS_PROGRAMS 63
+#define PLAYER_HAS_RESOLUTIONS 64
+#define PLAYER_FRAMEADVANCE 65
+#define PLAYER_ICON 66
+#define PLAYER_CUTLIST 67
+#define PLAYER_CHAPTERS 68
+#define PLAYER_EDITLIST 69
+#define PLAYER_CUTS 70
+#define PLAYER_SCENE_MARKERS 71
+#define PLAYER_HAS_SCENE_MARKERS 72
+// Keep player infolabels that work with offset and position together
+#define PLAYER_PATH 81
+#define PLAYER_FILEPATH 82
+#define PLAYER_TITLE 83
+#define PLAYER_FILENAME 84
+
+// Range of player infolabels that work with offset and position
+#define PLAYER_OFFSET_POSITION_FIRST PLAYER_PATH
+#define PLAYER_OFFSET_POSITION_LAST PLAYER_FILENAME
+
+#define WEATHER_CONDITIONS_TEXT 100
+#define WEATHER_TEMPERATURE 101
+#define WEATHER_LOCATION 102
+#define WEATHER_IS_FETCHED 103
+#define WEATHER_FANART_CODE 104
+#define WEATHER_PLUGIN 105
+#define WEATHER_CONDITIONS_ICON 106
+
+#define SYSTEM_TEMPERATURE_UNITS 107
+#define SYSTEM_PROGRESS_BAR 108
+#define SYSTEM_LANGUAGE 109
+#define SYSTEM_TIME 110
+#define SYSTEM_DATE 111
+#define SYSTEM_CPU_TEMPERATURE 112
+#define SYSTEM_GPU_TEMPERATURE 113
+#define SYSTEM_FAN_SPEED 114
+#define SYSTEM_FREE_SPACE_C 115
+// #define SYSTEM_FREE_SPACE_D 116 //116 is reserved for space on D
+#define SYSTEM_FREE_SPACE_E 117
+#define SYSTEM_FREE_SPACE_F 118
+#define SYSTEM_FREE_SPACE_G 119
+#define SYSTEM_BUILD_VERSION 120
+#define SYSTEM_BUILD_DATE 121
+#define SYSTEM_ETHERNET_LINK_ACTIVE 122
+#define SYSTEM_FPS 123
+#define SYSTEM_ALWAYS_TRUE 125 // useful for <visible fade="10" start="hidden">true</visible>, to fade in a control
+#define SYSTEM_ALWAYS_FALSE 126 // used for <visible fade="10">false</visible>, to fade out a control (ie not particularly useful!)
+#define SYSTEM_MEDIA_DVD 127
+#define SYSTEM_DVDREADY 128
+#define SYSTEM_HAS_ALARM 129
+#define SYSTEM_SUPPORTS_CPU_USAGE 130
+#define SYSTEM_SCREEN_MODE 132
+#define SYSTEM_SCREEN_WIDTH 133
+#define SYSTEM_SCREEN_HEIGHT 134
+#define SYSTEM_CURRENT_WINDOW 135
+#define SYSTEM_CURRENT_CONTROL 136
+#define SYSTEM_CURRENT_CONTROL_ID 137
+#define SYSTEM_DVD_LABEL 138
+#define SYSTEM_HASLOCKS 140
+#define SYSTEM_ISMASTER 141
+#define SYSTEM_TRAYOPEN 142
+#define SYSTEM_SHOW_EXIT_BUTTON 143
+#define SYSTEM_ALARM_POS 144
+#define SYSTEM_LOGGEDON 145
+#define SYSTEM_PROFILENAME 146
+#define SYSTEM_PROFILETHUMB 147
+#define SYSTEM_HAS_LOGINSCREEN 148
+#define SYSTEM_HAS_ACTIVE_MODAL_DIALOG 149
+#define SYSTEM_HDD_SMART 150
+#define SYSTEM_HDD_TEMPERATURE 151
+#define SYSTEM_HDD_MODEL 152
+#define SYSTEM_HDD_SERIAL 153
+#define SYSTEM_HDD_FIRMWARE 154
+#define SYSTEM_HAS_VISIBLE_MODAL_DIALOG 155
+#define SYSTEM_HDD_PASSWORD 156
+#define SYSTEM_HDD_LOCKSTATE 157
+#define SYSTEM_HDD_LOCKKEY 158
+#define SYSTEM_INTERNET_STATE 159
+#define SYSTEM_HAS_INPUT_HIDDEN 160
+#define SYSTEM_HAS_PVR_ADDON 161
+#define SYSTEM_ALARM_LESS_OR_EQUAL 180
+#define SYSTEM_PROFILECOUNT 181
+#define SYSTEM_ISFULLSCREEN 182
+#define SYSTEM_ISSTANDALONE 183
+#define SYSTEM_IDLE_SHUTDOWN_INHIBITED 184
+#define SYSTEM_HAS_SHUTDOWN 185
+#define SYSTEM_HAS_PVR 186
+#define SYSTEM_STARTUP_WINDOW 187
+#define SYSTEM_STEREOSCOPIC_MODE 188
+#define SYSTEM_BUILD_VERSION_SHORT 189
+
+#define NETWORK_IP_ADDRESS 190
+#define NETWORK_MAC_ADDRESS 191
+#define NETWORK_IS_DHCP 192
+#define NETWORK_LINK_STATE 193
+#define NETWORK_SUBNET_MASK 194
+#define NETWORK_GATEWAY_ADDRESS 195
+#define NETWORK_DNS1_ADDRESS 196
+#define NETWORK_DNS2_ADDRESS 197
+#define NETWORK_DHCP_ADDRESS 198
+
+// Keep musicplayer infolabels that work with offset and position together
+#define MUSICPLAYER_TITLE 200
+#define MUSICPLAYER_ALBUM 201
+#define MUSICPLAYER_ARTIST 202
+#define MUSICPLAYER_GENRE 203
+#define MUSICPLAYER_YEAR 204
+#define MUSICPLAYER_DURATION 205
+#define MUSICPLAYER_TRACK_NUMBER 208
+#define MUSICPLAYER_COVER 210
+#define MUSICPLAYER_BITRATE 211
+#define MUSICPLAYER_PLAYLISTLEN 212
+#define MUSICPLAYER_PLAYLISTPOS 213
+#define MUSICPLAYER_CHANNELS 214
+#define MUSICPLAYER_BITSPERSAMPLE 215
+#define MUSICPLAYER_SAMPLERATE 216
+#define MUSICPLAYER_CODEC 217
+#define MUSICPLAYER_DISC_NUMBER 218
+#define MUSICPLAYER_RATING 219
+#define MUSICPLAYER_COMMENT 220
+#define MUSICPLAYER_LYRICS 221
+#define MUSICPLAYER_ALBUM_ARTIST 222
+#define MUSICPLAYER_PLAYCOUNT 223
+#define MUSICPLAYER_LASTPLAYED 224
+#define MUSICPLAYER_USER_RATING 225
+#define MUSICPLAYER_RATING_AND_VOTES 226
+#define MUSICPLAYER_VOTES 227
+#define MUSICPLAYER_MOOD 228
+#define MUSICPLAYER_CONTRIBUTORS 229
+#define MUSICPLAYER_CONTRIBUTOR_AND_ROLE 230
+#define MUSICPLAYER_DBID 231
+#define MUSICPLAYER_DISC_TITLE 232
+#define MUSICPLAYER_RELEASEDATE 233
+#define MUSICPLAYER_ORIGINALDATE 234
+#define MUSICPLAYER_BPM 235
+
+// Range of musicplayer infolabels that work with offset and position
+#define MUSICPLAYER_OFFSET_POSITION_FIRST MUSICPLAYER_TITLE
+#define MUSICPLAYER_OFFSET_POSITION_LAST MUSICPLAYER_BPM
+
+#define MUSICPLAYER_PROPERTY 236
+#define MUSICPLAYER_CHANNEL_NAME 237
+#define MUSICPLAYER_CHANNEL_GROUP 238
+#define MUSICPLAYER_CHANNEL_NUMBER 239
+#define MUSICPLAYER_TOTALDISCS 240
+#define MUSICPLAYER_STATIONNAME 241
+
+// Musicplayer infobools
+#define MUSICPLAYER_HASPREVIOUS 242
+#define MUSICPLAYER_HASNEXT 243
+#define MUSICPLAYER_EXISTS 244
+#define MUSICPLAYER_PLAYLISTPLAYING 245
+#define MUSICPLAYER_CONTENT 246
+#define MUSICPLAYER_ISMULTIDISC 247
+
+// Videoplayer infolabels
+#define VIDEOPLAYER_HDR_TYPE 249
+// Keep videoplayer infolabels that work with offset and position together
+#define VIDEOPLAYER_TITLE 250
+#define VIDEOPLAYER_GENRE 251
+#define VIDEOPLAYER_DIRECTOR 252
+#define VIDEOPLAYER_YEAR 253
+#define VIDEOPLAYER_COVER 254
+#define VIDEOPLAYER_ORIGINALTITLE 255
+#define VIDEOPLAYER_PLOT 256
+#define VIDEOPLAYER_PLOT_OUTLINE 257
+#define VIDEOPLAYER_EPISODE 258
+#define VIDEOPLAYER_SEASON 259
+#define VIDEOPLAYER_RATING 260
+#define VIDEOPLAYER_TVSHOW 261
+#define VIDEOPLAYER_PREMIERED 262
+#define VIDEOPLAYER_STUDIO 263
+#define VIDEOPLAYER_MPAA 264
+#define VIDEOPLAYER_ARTIST 265
+#define VIDEOPLAYER_ALBUM 266
+#define VIDEOPLAYER_WRITER 267
+#define VIDEOPLAYER_TAGLINE 268
+#define VIDEOPLAYER_TOP250 269
+#define VIDEOPLAYER_RATING_AND_VOTES 270
+#define VIDEOPLAYER_TRAILER 271
+#define VIDEOPLAYER_COUNTRY 272
+#define VIDEOPLAYER_PLAYCOUNT 273
+#define VIDEOPLAYER_LASTPLAYED 274
+#define VIDEOPLAYER_VOTES 275
+#define VIDEOPLAYER_IMDBNUMBER 276
+#define VIDEOPLAYER_USER_RATING 277
+#define VIDEOPLAYER_DBID 278
+#define VIDEOPLAYER_TVSHOWDBID 279
+#define VIDEOPLAYER_ART 280
+
+// Range of videoplayer infolabels that work with offset and position
+#define VIDEOPLAYER_OFFSET_POSITION_FIRST VIDEOPLAYER_TITLE
+#define VIDEOPLAYER_OFFSET_POSITION_LAST VIDEOPLAYER_ART
+
+#define VIDEOPLAYER_AUDIO_BITRATE 281
+#define VIDEOPLAYER_VIDEO_BITRATE 282
+#define VIDEOPLAYER_VIDEO_CODEC 283
+#define VIDEOPLAYER_VIDEO_RESOLUTION 284
+#define VIDEOPLAYER_AUDIO_CODEC 285
+#define VIDEOPLAYER_AUDIO_CHANNELS 286
+#define VIDEOPLAYER_VIDEO_ASPECT 287
+#define VIDEOPLAYER_SUBTITLES_LANG 288
+#define VIDEOPLAYER_AUDIO_LANG 290
+#define VIDEOPLAYER_STEREOSCOPIC_MODE 291
+#define VIDEOPLAYER_CAST 292
+#define VIDEOPLAYER_CAST_AND_ROLE 293
+#define VIDEOPLAYER_UNIQUEID 294
+#define VIDEOPLAYER_AUDIOSTREAMCOUNT 295
+
+// Videoplayer infobools
+#define VIDEOPLAYER_HASSUBTITLES 300
+#define VIDEOPLAYER_SUBTITLESENABLED 301
+#define VIDEOPLAYER_USING_OVERLAYS 302
+#define VIDEOPLAYER_ISFULLSCREEN 303
+#define VIDEOPLAYER_HASMENU 304
+#define VIDEOPLAYER_PLAYLISTLEN 305
+#define VIDEOPLAYER_PLAYLISTPOS 306
+#define VIDEOPLAYER_CONTENT 307
+#define VIDEOPLAYER_HAS_INFO 308
+#define VIDEOPLAYER_HASTELETEXT 309
+#define VIDEOPLAYER_IS_STEREOSCOPIC 310
+
+// PVR infolabels
+#define VIDEOPLAYER_EVENT 313
+#define VIDEOPLAYER_EPISODENAME 314
+#define VIDEOPLAYER_STARTTIME 315
+#define VIDEOPLAYER_ENDTIME 316
+#define VIDEOPLAYER_NEXT_TITLE 317
+#define VIDEOPLAYER_NEXT_GENRE 318
+#define VIDEOPLAYER_NEXT_PLOT 319
+#define VIDEOPLAYER_NEXT_PLOT_OUTLINE 320
+#define VIDEOPLAYER_NEXT_STARTTIME 321
+#define VIDEOPLAYER_NEXT_ENDTIME 322
+#define VIDEOPLAYER_NEXT_DURATION 323
+#define VIDEOPLAYER_CHANNEL_NAME 324
+#define VIDEOPLAYER_CHANNEL_GROUP 325
+#define VIDEOPLAYER_PARENTAL_RATING 326
+#define VIDEOPLAYER_CHANNEL_NUMBER 327
+
+// PVR infobools
+#define VIDEOPLAYER_HAS_EPG 328
+#define VIDEOPLAYER_CAN_RESUME_LIVE_TV 329
+
+#define RETROPLAYER_VIDEO_FILTER 330
+#define RETROPLAYER_STRETCH_MODE 331
+#define RETROPLAYER_VIDEO_ROTATION 332
+
+#define CONTAINER_HAS_PARENT_ITEM 341
+#define CONTAINER_CAN_FILTER 342
+#define CONTAINER_CAN_FILTERADVANCED 343
+#define CONTAINER_FILTERED 344
+
+#define CONTAINER_SCROLL_PREVIOUS 345
+#define CONTAINER_MOVE_PREVIOUS 346
+// unused 347
+#define CONTAINER_MOVE_NEXT 348
+#define CONTAINER_SCROLL_NEXT 349
+#define CONTAINER_ISUPDATING 350
+#define CONTAINER_HASFILES 351
+#define CONTAINER_HASFOLDERS 352
+#define CONTAINER_STACKED 353
+#define CONTAINER_FOLDERNAME 354
+#define CONTAINER_SCROLLING 355
+#define CONTAINER_PLUGINNAME 356
+#define CONTAINER_PROPERTY 357
+#define CONTAINER_SORT_DIRECTION 358
+#define CONTAINER_NUM_ITEMS 359
+#define CONTAINER_FOLDERPATH 360
+#define CONTAINER_CONTENT 361
+#define CONTAINER_HAS_THUMB 362
+#define CONTAINER_SORT_METHOD 363
+#define CONTAINER_CURRENT_ITEM 364
+#define CONTAINER_ART 365
+#define CONTAINER_HAS_FOCUS 366
+#define CONTAINER_ROW 367
+#define CONTAINER_COLUMN 368
+#define CONTAINER_POSITION 369
+#define CONTAINER_VIEWMODE 370
+#define CONTAINER_HAS_NEXT 371
+#define CONTAINER_HAS_PREVIOUS 372
+#define CONTAINER_SUBITEM 373
+#define CONTAINER_NUM_PAGES 374
+#define CONTAINER_CURRENT_PAGE 375
+#define CONTAINER_SHOWPLOT 376
+#define CONTAINER_TOTALTIME 377
+#define CONTAINER_SORT_ORDER 378
+#define CONTAINER_TOTALWATCHED 379
+#define CONTAINER_TOTALUNWATCHED 380
+#define CONTAINER_VIEWCOUNT 381
+#define CONTAINER_SHOWTITLE 382
+#define CONTAINER_PLUGINCATEGORY 383
+#define CONTAINER_NUM_ALL_ITEMS 384
+#define CONTAINER_NUM_NONFOLDER_ITEMS 385
+
+#define MUSICPM_ENABLED 390
+#define MUSICPM_SONGSPLAYED 391
+#define MUSICPM_MATCHINGSONGS 392
+#define MUSICPM_MATCHINGSONGSPICKED 393
+#define MUSICPM_MATCHINGSONGSLEFT 394
+#define MUSICPM_RELAXEDSONGSPICKED 395
+#define MUSICPM_RANDOMSONGSPICKED 396
+
+#define PLAYLIST_LENGTH 400
+#define PLAYLIST_POSITION 401
+#define PLAYLIST_RANDOM 402
+#define PLAYLIST_REPEAT 403
+#define PLAYLIST_ISRANDOM 404
+#define PLAYLIST_ISREPEAT 405
+#define PLAYLIST_ISREPEATONE 406
+
+#define VISUALISATION_LOCKED 410
+#define VISUALISATION_PRESET 411
+#define VISUALISATION_NAME 412
+#define VISUALISATION_ENABLED 413
+#define VISUALISATION_HAS_PRESETS 414
+
+#define STRING_IS_EMPTY 420
+#define STRING_IS_EQUAL 421
+#define STRING_STARTS_WITH 422
+#define STRING_ENDS_WITH 423
+#define STRING_CONTAINS 424
+
+#define INTEGER_IS_EQUAL 450
+#define INTEGER_GREATER_THAN 451
+#define INTEGER_GREATER_OR_EQUAL 452
+#define INTEGER_LESS_THAN 453
+#define INTEGER_LESS_OR_EQUAL 454
+#define INTEGER_EVEN 455
+#define INTEGER_ODD 456
+#define INTEGER_VALUEOF 457
+
+#define SKIN_BOOL 600
+#define SKIN_STRING 601
+#define SKIN_STRING_IS_EQUAL 602
+#define SKIN_THEME 604
+#define SKIN_COLOUR_THEME 605
+#define SKIN_HAS_THEME 606
+#define SKIN_ASPECT_RATIO 607
+#define SKIN_FONT 608
+#define SKIN_INTEGER 609
+#define SKIN_TIMER_IS_RUNNING 610
+#define SKIN_TIMER_ELAPSEDSECS 611
+
+#define SYSTEM_IS_SCREENSAVER_INHIBITED 641
+#define SYSTEM_ADDON_UPDATE_COUNT 642
+#define SYSTEM_PRIVACY_POLICY 643
+#define SYSTEM_TOTAL_MEMORY 644
+#define SYSTEM_CPU_USAGE 645
+#define SYSTEM_USED_MEMORY_PERCENT 646
+#define SYSTEM_USED_MEMORY 647
+#define SYSTEM_FREE_MEMORY 648
+#define SYSTEM_FREE_MEMORY_PERCENT 649
+#define SYSTEM_UPTIME 654
+#define SYSTEM_TOTALUPTIME 655
+#define SYSTEM_CPUFREQUENCY 656
+#define SYSTEM_SCREEN_RESOLUTION 659
+#define SYSTEM_VIDEO_ENCODER_INFO 660
+#define SYSTEM_OS_VERSION_INFO 667
+#define SYSTEM_FREE_SPACE 679
+#define SYSTEM_USED_SPACE 680
+#define SYSTEM_TOTAL_SPACE 681
+#define SYSTEM_USED_SPACE_PERCENT 682
+#define SYSTEM_FREE_SPACE_PERCENT 683
+#define SYSTEM_ADDON_IS_ENABLED 703
+#define SYSTEM_GET_BOOL 704
+#define SYSTEM_GET_CORE_USAGE 705
+#define SYSTEM_HAS_CORE_ID 706
+#define SYSTEM_RENDER_VENDOR 707
+#define SYSTEM_RENDER_RENDERER 708
+#define SYSTEM_RENDER_VERSION 709
+#define SYSTEM_SETTING 710
+#define SYSTEM_HAS_ADDON 711
+#define SYSTEM_ADDON_TITLE 712
+#define SYSTEM_ADDON_ICON 713
+#define SYSTEM_BATTERY_LEVEL 714
+#define SYSTEM_IDLE_TIME 715
+#define SYSTEM_FRIENDLY_NAME 716
+#define SYSTEM_SCREENSAVER_ACTIVE 717
+#define SYSTEM_ADDON_VERSION 718
+#define SYSTEM_DPMS_ACTIVE 719
+
+#define LIBRARY_HAS_MUSIC 720
+#define LIBRARY_HAS_VIDEO 721
+#define LIBRARY_HAS_MOVIES 722
+#define LIBRARY_HAS_MOVIE_SETS 723
+#define LIBRARY_HAS_TVSHOWS 724
+#define LIBRARY_HAS_MUSICVIDEOS 725
+#define LIBRARY_HAS_SINGLES 726
+#define LIBRARY_HAS_COMPILATIONS 727
+#define LIBRARY_IS_SCANNING 728
+#define LIBRARY_IS_SCANNING_VIDEO 729
+#define LIBRARY_IS_SCANNING_MUSIC 730
+#define LIBRARY_HAS_ROLE 735
+#define LIBRARY_HAS_BOXSETS 736
+#define LIBRARY_HAS_NODE 737
+
+#define SYSTEM_PLATFORM_LINUX 741
+#define SYSTEM_PLATFORM_WINDOWS 742
+#define SYSTEM_PLATFORM_DARWIN 743
+#define SYSTEM_PLATFORM_DARWIN_OSX 744
+#define SYSTEM_PLATFORM_DARWIN_IOS 745
+#define SYSTEM_PLATFORM_UWP 746
+#define SYSTEM_PLATFORM_ANDROID 747
+#define SYSTEM_PLATFORM_WINDOWING 748
+#define SYSTEM_PLATFORM_WIN10 749
+
+#define SYSTEM_CAN_POWERDOWN 750
+#define SYSTEM_CAN_SUSPEND 751
+#define SYSTEM_CAN_HIBERNATE 752
+#define SYSTEM_CAN_REBOOT 753
+#define SYSTEM_MEDIA_AUDIO_CD 754
+
+#define SYSTEM_PLATFORM_DARWIN_TVOS 755
+#define SYSTEM_SUPPORTED_HDR_TYPES 756
+
+#define SLIDESHOW_ISPAUSED 800
+#define SLIDESHOW_ISRANDOM 801
+#define SLIDESHOW_ISACTIVE 802
+#define SLIDESHOW_ISVIDEO 803
+
+#define SLIDESHOW_LABELS_START 900
+#define SLIDESHOW_FILE_NAME (SLIDESHOW_LABELS_START)
+#define SLIDESHOW_FILE_PATH (SLIDESHOW_LABELS_START + 1)
+#define SLIDESHOW_FILE_SIZE (SLIDESHOW_LABELS_START + 2)
+#define SLIDESHOW_FILE_DATE (SLIDESHOW_LABELS_START + 3)
+#define SLIDESHOW_INDEX (SLIDESHOW_LABELS_START + 4)
+#define SLIDESHOW_RESOLUTION (SLIDESHOW_LABELS_START + 5)
+#define SLIDESHOW_COMMENT (SLIDESHOW_LABELS_START + 6)
+#define SLIDESHOW_COLOUR (SLIDESHOW_LABELS_START + 7)
+#define SLIDESHOW_PROCESS (SLIDESHOW_LABELS_START + 8)
+
+#define SLIDESHOW_EXIF_LONG_DATE (SLIDESHOW_LABELS_START + 17)
+#define SLIDESHOW_EXIF_LONG_DATE_TIME (SLIDESHOW_LABELS_START + 18)
+#define SLIDESHOW_EXIF_DATE (SLIDESHOW_LABELS_START + 19) /* Implementation only to just get localized date */
+#define SLIDESHOW_EXIF_DATE_TIME (SLIDESHOW_LABELS_START + 20)
+#define SLIDESHOW_EXIF_DESCRIPTION (SLIDESHOW_LABELS_START + 21)
+#define SLIDESHOW_EXIF_CAMERA_MAKE (SLIDESHOW_LABELS_START + 22)
+#define SLIDESHOW_EXIF_CAMERA_MODEL (SLIDESHOW_LABELS_START + 23)
+#define SLIDESHOW_EXIF_COMMENT (SLIDESHOW_LABELS_START + 24)
+#define SLIDESHOW_EXIF_SOFTWARE (SLIDESHOW_LABELS_START + 25)
+#define SLIDESHOW_EXIF_APERTURE (SLIDESHOW_LABELS_START + 26)
+#define SLIDESHOW_EXIF_FOCAL_LENGTH (SLIDESHOW_LABELS_START + 27)
+#define SLIDESHOW_EXIF_FOCUS_DIST (SLIDESHOW_LABELS_START + 28)
+#define SLIDESHOW_EXIF_EXPOSURE (SLIDESHOW_LABELS_START + 29)
+#define SLIDESHOW_EXIF_EXPOSURE_TIME (SLIDESHOW_LABELS_START + 30)
+#define SLIDESHOW_EXIF_EXPOSURE_BIAS (SLIDESHOW_LABELS_START + 31)
+#define SLIDESHOW_EXIF_EXPOSURE_MODE (SLIDESHOW_LABELS_START + 32)
+#define SLIDESHOW_EXIF_FLASH_USED (SLIDESHOW_LABELS_START + 33)
+#define SLIDESHOW_EXIF_WHITE_BALANCE (SLIDESHOW_LABELS_START + 34)
+#define SLIDESHOW_EXIF_LIGHT_SOURCE (SLIDESHOW_LABELS_START + 35)
+#define SLIDESHOW_EXIF_METERING_MODE (SLIDESHOW_LABELS_START + 36)
+#define SLIDESHOW_EXIF_ISO_EQUIV (SLIDESHOW_LABELS_START + 37)
+#define SLIDESHOW_EXIF_DIGITAL_ZOOM (SLIDESHOW_LABELS_START + 38)
+#define SLIDESHOW_EXIF_CCD_WIDTH (SLIDESHOW_LABELS_START + 39)
+#define SLIDESHOW_EXIF_GPS_LATITUDE (SLIDESHOW_LABELS_START + 40)
+#define SLIDESHOW_EXIF_GPS_LONGITUDE (SLIDESHOW_LABELS_START + 41)
+#define SLIDESHOW_EXIF_GPS_ALTITUDE (SLIDESHOW_LABELS_START + 42)
+#define SLIDESHOW_EXIF_ORIENTATION (SLIDESHOW_LABELS_START + 43)
+#define SLIDESHOW_EXIF_XPCOMMENT (SLIDESHOW_LABELS_START + 44)
+
+#define SLIDESHOW_IPTC_SUBLOCATION (SLIDESHOW_LABELS_START + 57)
+#define SLIDESHOW_IPTC_IMAGETYPE (SLIDESHOW_LABELS_START + 58)
+#define SLIDESHOW_IPTC_TIMECREATED (SLIDESHOW_LABELS_START + 59)
+#define SLIDESHOW_IPTC_SUP_CATEGORIES (SLIDESHOW_LABELS_START + 60)
+#define SLIDESHOW_IPTC_KEYWORDS (SLIDESHOW_LABELS_START + 61)
+#define SLIDESHOW_IPTC_CAPTION (SLIDESHOW_LABELS_START + 62)
+#define SLIDESHOW_IPTC_AUTHOR (SLIDESHOW_LABELS_START + 63)
+#define SLIDESHOW_IPTC_HEADLINE (SLIDESHOW_LABELS_START + 64)
+#define SLIDESHOW_IPTC_SPEC_INSTR (SLIDESHOW_LABELS_START + 65)
+#define SLIDESHOW_IPTC_CATEGORY (SLIDESHOW_LABELS_START + 66)
+#define SLIDESHOW_IPTC_BYLINE (SLIDESHOW_LABELS_START + 67)
+#define SLIDESHOW_IPTC_BYLINE_TITLE (SLIDESHOW_LABELS_START + 68)
+#define SLIDESHOW_IPTC_CREDIT (SLIDESHOW_LABELS_START + 69)
+#define SLIDESHOW_IPTC_SOURCE (SLIDESHOW_LABELS_START + 70)
+#define SLIDESHOW_IPTC_COPYRIGHT_NOTICE (SLIDESHOW_LABELS_START + 71)
+#define SLIDESHOW_IPTC_OBJECT_NAME (SLIDESHOW_LABELS_START + 72)
+#define SLIDESHOW_IPTC_CITY (SLIDESHOW_LABELS_START + 73)
+#define SLIDESHOW_IPTC_STATE (SLIDESHOW_LABELS_START + 74)
+#define SLIDESHOW_IPTC_COUNTRY (SLIDESHOW_LABELS_START + 75)
+#define SLIDESHOW_IPTC_TX_REFERENCE (SLIDESHOW_LABELS_START + 76)
+#define SLIDESHOW_IPTC_DATE (SLIDESHOW_LABELS_START + 77)
+#define SLIDESHOW_IPTC_URGENCY (SLIDESHOW_LABELS_START + 78)
+#define SLIDESHOW_IPTC_COUNTRY_CODE (SLIDESHOW_LABELS_START + 79)
+#define SLIDESHOW_IPTC_REF_SERVICE (SLIDESHOW_LABELS_START + 80)
+#define SLIDESHOW_LABELS_END SLIDESHOW_IPTC_REF_SERVICE
+
+#define FANART_COLOR1 1000
+#define FANART_COLOR2 1001
+#define FANART_COLOR3 1002
+#define FANART_IMAGE 1003
+
+#define SYSTEM_PROFILEAUTOLOGIN 1004
+
+#define SYSTEM_HAS_CMS 1006
+#define SYSTEM_BUILD_VERSION_CODE 1007
+#define SYSTEM_BUILD_VERSION_GIT 1008
+
+#define PVR_CONDITIONS_START 1100
+#define PVR_IS_RECORDING (PVR_CONDITIONS_START)
+#define PVR_HAS_TIMER (PVR_CONDITIONS_START + 1)
+#define PVR_HAS_NONRECORDING_TIMER (PVR_CONDITIONS_START + 2)
+#define PVR_IS_PLAYING_TV (PVR_CONDITIONS_START + 3)
+#define PVR_IS_PLAYING_RADIO (PVR_CONDITIONS_START + 4)
+#define PVR_IS_PLAYING_RECORDING (PVR_CONDITIONS_START + 5)
+#define PVR_ACTUAL_STREAM_ENCRYPTED (PVR_CONDITIONS_START + 6)
+#define PVR_HAS_TV_CHANNELS (PVR_CONDITIONS_START + 7)
+#define PVR_HAS_RADIO_CHANNELS (PVR_CONDITIONS_START + 8)
+#define PVR_IS_TIMESHIFTING (PVR_CONDITIONS_START + 9)
+#define PVR_IS_RECORDING_TV (PVR_CONDITIONS_START + 10)
+#define PVR_HAS_TV_TIMER (PVR_CONDITIONS_START + 11)
+#define PVR_HAS_NONRECORDING_TV_TIMER (PVR_CONDITIONS_START + 12)
+#define PVR_IS_RECORDING_RADIO (PVR_CONDITIONS_START + 13)
+#define PVR_HAS_RADIO_TIMER (PVR_CONDITIONS_START + 14)
+#define PVR_HAS_NONRECORDING_RADIO_TIMER (PVR_CONDITIONS_START + 15)
+#define PVR_IS_PLAYING_EPGTAG (PVR_CONDITIONS_START + 16)
+#define PVR_CAN_RECORD_PLAYING_CHANNEL (PVR_CONDITIONS_START + 17)
+#define PVR_IS_RECORDING_PLAYING_CHANNEL (PVR_CONDITIONS_START + 18)
+#define PVR_IS_PLAYING_ACTIVE_RECORDING (PVR_CONDITIONS_START + 19)
+#define PVR_CONDITIONS_END PVR_IS_PLAYING_ACTIVE_RECORDING
+
+#define PVR_STRINGS_START 1200
+#define PVR_NEXT_RECORDING_CHANNEL (PVR_STRINGS_START)
+#define PVR_NEXT_RECORDING_CHAN_ICO (PVR_STRINGS_START + 1)
+#define PVR_NEXT_RECORDING_DATETIME (PVR_STRINGS_START + 2)
+#define PVR_NEXT_RECORDING_TITLE (PVR_STRINGS_START + 3)
+#define PVR_NOW_RECORDING_CHANNEL (PVR_STRINGS_START + 4)
+#define PVR_NOW_RECORDING_CHAN_ICO (PVR_STRINGS_START + 5)
+#define PVR_NOW_RECORDING_DATETIME (PVR_STRINGS_START + 6)
+#define PVR_NOW_RECORDING_TITLE (PVR_STRINGS_START + 7)
+#define PVR_BACKEND_NAME (PVR_STRINGS_START + 8)
+#define PVR_BACKEND_VERSION (PVR_STRINGS_START + 9)
+#define PVR_BACKEND_HOST (PVR_STRINGS_START + 10)
+#define PVR_BACKEND_DISKSPACE (PVR_STRINGS_START + 11)
+#define PVR_BACKEND_CHANNELS (PVR_STRINGS_START + 12)
+#define PVR_BACKEND_TIMERS (PVR_STRINGS_START + 13)
+#define PVR_BACKEND_RECORDINGS (PVR_STRINGS_START + 14)
+#define PVR_BACKEND_DELETED_RECORDINGS (PVR_STRINGS_START + 15)
+#define PVR_BACKEND_NUMBER (PVR_STRINGS_START + 16)
+#define PVR_TOTAL_DISKSPACE (PVR_STRINGS_START + 17)
+#define PVR_NEXT_TIMER (PVR_STRINGS_START + 18)
+#define PVR_EPG_EVENT_DURATION (PVR_STRINGS_START + 19)
+#define PVR_EPG_EVENT_ELAPSED_TIME (PVR_STRINGS_START + 20)
+#define PVR_EPG_EVENT_PROGRESS (PVR_STRINGS_START + 21)
+#define PVR_ACTUAL_STREAM_CLIENT (PVR_STRINGS_START + 22)
+#define PVR_ACTUAL_STREAM_DEVICE (PVR_STRINGS_START + 23)
+#define PVR_ACTUAL_STREAM_STATUS (PVR_STRINGS_START + 24)
+#define PVR_ACTUAL_STREAM_SIG (PVR_STRINGS_START + 25)
+#define PVR_ACTUAL_STREAM_SNR (PVR_STRINGS_START + 26)
+#define PVR_ACTUAL_STREAM_SIG_PROGR (PVR_STRINGS_START + 27)
+#define PVR_ACTUAL_STREAM_SNR_PROGR (PVR_STRINGS_START + 28)
+#define PVR_ACTUAL_STREAM_BER (PVR_STRINGS_START + 29)
+#define PVR_ACTUAL_STREAM_UNC (PVR_STRINGS_START + 30)
+#define PVR_ACTUAL_STREAM_CRYPTION (PVR_STRINGS_START + 34)
+#define PVR_ACTUAL_STREAM_SERVICE (PVR_STRINGS_START + 35)
+#define PVR_ACTUAL_STREAM_MUX (PVR_STRINGS_START + 36)
+#define PVR_ACTUAL_STREAM_PROVIDER (PVR_STRINGS_START + 37)
+#define PVR_BACKEND_DISKSPACE_PROGR (PVR_STRINGS_START + 38)
+#define PVR_TIMESHIFT_START_TIME (PVR_STRINGS_START + 39)
+#define PVR_TIMESHIFT_END_TIME (PVR_STRINGS_START + 40)
+#define PVR_TIMESHIFT_PLAY_TIME (PVR_STRINGS_START + 41)
+#define PVR_TIMESHIFT_PROGRESS (PVR_STRINGS_START + 42)
+#define PVR_TV_NOW_RECORDING_TITLE (PVR_STRINGS_START + 43)
+#define PVR_TV_NOW_RECORDING_CHANNEL (PVR_STRINGS_START + 44)
+#define PVR_TV_NOW_RECORDING_CHAN_ICO (PVR_STRINGS_START + 45)
+#define PVR_TV_NOW_RECORDING_DATETIME (PVR_STRINGS_START + 46)
+#define PVR_TV_NEXT_RECORDING_TITLE (PVR_STRINGS_START + 47)
+#define PVR_TV_NEXT_RECORDING_CHANNEL (PVR_STRINGS_START + 48)
+#define PVR_TV_NEXT_RECORDING_CHAN_ICO (PVR_STRINGS_START + 49)
+#define PVR_TV_NEXT_RECORDING_DATETIME (PVR_STRINGS_START + 50)
+#define PVR_RADIO_NOW_RECORDING_TITLE (PVR_STRINGS_START + 51)
+#define PVR_RADIO_NOW_RECORDING_CHANNEL (PVR_STRINGS_START + 52)
+#define PVR_RADIO_NOW_RECORDING_CHAN_ICO (PVR_STRINGS_START + 53)
+#define PVR_RADIO_NOW_RECORDING_DATETIME (PVR_STRINGS_START + 54)
+#define PVR_RADIO_NEXT_RECORDING_TITLE (PVR_STRINGS_START + 55)
+#define PVR_RADIO_NEXT_RECORDING_CHANNEL (PVR_STRINGS_START + 56)
+#define PVR_RADIO_NEXT_RECORDING_CHAN_ICO (PVR_STRINGS_START + 57)
+#define PVR_RADIO_NEXT_RECORDING_DATETIME (PVR_STRINGS_START + 58)
+#define PVR_CHANNEL_NUMBER_INPUT (PVR_STRINGS_START + 59)
+#define PVR_EPG_EVENT_REMAINING_TIME (PVR_STRINGS_START + 60)
+#define PVR_EPG_EVENT_FINISH_TIME (PVR_STRINGS_START + 61)
+#define PVR_TIMESHIFT_OFFSET (PVR_STRINGS_START + 62)
+#define PVR_EPG_EVENT_SEEK_TIME (PVR_STRINGS_START + 63)
+#define PVR_TIMESHIFT_PROGRESS_PLAY_POS (PVR_STRINGS_START + 64)
+#define PVR_TIMESHIFT_PROGRESS_DURATION (PVR_STRINGS_START + 65)
+#define PVR_TIMESHIFT_PROGRESS_EPG_START (PVR_STRINGS_START + 66)
+#define PVR_TIMESHIFT_PROGRESS_EPG_END (PVR_STRINGS_START + 67)
+#define PVR_TIMESHIFT_PROGRESS_BUFFER_START (PVR_STRINGS_START + 68)
+#define PVR_TIMESHIFT_PROGRESS_BUFFER_END (PVR_STRINGS_START + 69)
+#define PVR_TIMESHIFT_PROGRESS_START_TIME (PVR_STRINGS_START + 70)
+#define PVR_TIMESHIFT_PROGRESS_END_TIME (PVR_STRINGS_START + 71)
+#define PVR_EPG_EVENT_ICON (PVR_STRINGS_START + 72)
+#define PVR_TIMESHIFT_SEEKBAR (PVR_STRINGS_START + 73)
+#define PVR_BACKEND_PROVIDERS (PVR_STRINGS_START + 74)
+#define PVR_BACKEND_CHANNEL_GROUPS (PVR_STRINGS_START + 75)
+#define PVR_STRINGS_END PVR_BACKEND_CHANNEL_GROUPS
+
+#define RDS_DATA_START 1400
+#define RDS_HAS_RDS (RDS_DATA_START)
+#define RDS_HAS_RADIOTEXT (RDS_DATA_START + 1)
+#define RDS_HAS_RADIOTEXT_PLUS (RDS_DATA_START + 2)
+#define RDS_GET_RADIOTEXT_LINE (RDS_DATA_START + 3)
+#define RDS_TITLE (RDS_DATA_START + 4)
+#define RDS_BAND (RDS_DATA_START + 5)
+#define RDS_ARTIST (RDS_DATA_START + 6)
+#define RDS_COMPOSER (RDS_DATA_START + 7)
+#define RDS_CONDUCTOR (RDS_DATA_START + 8)
+#define RDS_ALBUM (RDS_DATA_START + 9)
+#define RDS_ALBUM_TRACKNUMBER (RDS_DATA_START + 10)
+#define RDS_GET_RADIO_STYLE (RDS_DATA_START + 11)
+#define RDS_COMMENT (RDS_DATA_START + 12)
+#define RDS_INFO_NEWS (RDS_DATA_START + 13)
+#define RDS_INFO_NEWS_LOCAL (RDS_DATA_START + 14)
+#define RDS_INFO_STOCK (RDS_DATA_START + 15)
+#define RDS_INFO_STOCK_SIZE (RDS_DATA_START + 16)
+#define RDS_INFO_SPORT (RDS_DATA_START + 17)
+#define RDS_INFO_SPORT_SIZE (RDS_DATA_START + 18)
+#define RDS_INFO_LOTTERY (RDS_DATA_START + 19)
+#define RDS_INFO_LOTTERY_SIZE (RDS_DATA_START + 20)
+#define RDS_INFO_WEATHER (RDS_DATA_START + 21)
+#define RDS_INFO_WEATHER_SIZE (RDS_DATA_START + 22)
+#define RDS_INFO_CINEMA (RDS_DATA_START + 23)
+#define RDS_INFO_CINEMA_SIZE (RDS_DATA_START + 24)
+#define RDS_INFO_HOROSCOPE (RDS_DATA_START + 25)
+#define RDS_INFO_HOROSCOPE_SIZE (RDS_DATA_START + 26)
+#define RDS_INFO_OTHER (RDS_DATA_START + 27)
+#define RDS_INFO_OTHER_SIZE (RDS_DATA_START + 28)
+#define RDS_PROG_STATION (RDS_DATA_START + 29)
+#define RDS_PROG_NOW (RDS_DATA_START + 30)
+#define RDS_PROG_NEXT (RDS_DATA_START + 31)
+#define RDS_PROG_HOST (RDS_DATA_START + 32)
+#define RDS_PROG_EDIT_STAFF (RDS_DATA_START + 33)
+#define RDS_PROG_HOMEPAGE (RDS_DATA_START + 34)
+#define RDS_PROG_STYLE (RDS_DATA_START + 35)
+#define RDS_PHONE_HOTLINE (RDS_DATA_START + 36)
+#define RDS_PHONE_STUDIO (RDS_DATA_START + 37)
+#define RDS_SMS_STUDIO (RDS_DATA_START + 38)
+#define RDS_EMAIL_HOTLINE (RDS_DATA_START + 39)
+#define RDS_EMAIL_STUDIO (RDS_DATA_START + 40)
+#define RDS_HAS_HOTLINE_DATA (RDS_DATA_START + 41)
+#define RDS_HAS_STUDIO_DATA (RDS_DATA_START + 42)
+#define RDS_AUDIO_LANG (RDS_DATA_START + 43)
+#define RDS_CHANNEL_COUNTRY (RDS_DATA_START + 44)
+#define RDS_DATA_END RDS_CHANNEL_COUNTRY
+
+#define PLAYER_PROCESS 1500
+#define PLAYER_PROCESS_VIDEODECODER (PLAYER_PROCESS)
+#define PLAYER_PROCESS_DEINTMETHOD (PLAYER_PROCESS + 1)
+#define PLAYER_PROCESS_PIXELFORMAT (PLAYER_PROCESS + 2)
+#define PLAYER_PROCESS_VIDEOWIDTH (PLAYER_PROCESS + 3)
+#define PLAYER_PROCESS_VIDEOHEIGHT (PLAYER_PROCESS + 4)
+#define PLAYER_PROCESS_VIDEOFPS (PLAYER_PROCESS + 5)
+#define PLAYER_PROCESS_VIDEODAR (PLAYER_PROCESS + 6)
+#define PLAYER_PROCESS_VIDEOHWDECODER (PLAYER_PROCESS + 7)
+#define PLAYER_PROCESS_AUDIODECODER (PLAYER_PROCESS + 8)
+#define PLAYER_PROCESS_AUDIOCHANNELS (PLAYER_PROCESS + 9)
+#define PLAYER_PROCESS_AUDIOSAMPLERATE (PLAYER_PROCESS + 10)
+#define PLAYER_PROCESS_AUDIOBITSPERSAMPLE (PLAYER_PROCESS + 11)
+#define PLAYER_PROCESS_VIDEOSCANTYPE (PLAYER_PROCESS + 12)
+
+#define ADDON_INFOS 1600
+#define ADDON_SETTING_STRING (ADDON_INFOS)
+#define ADDON_SETTING_BOOL (ADDON_INFOS + 1)
+#define ADDON_SETTING_INT (ADDON_INFOS + 2)
+
+#define WINDOW_PROPERTY 9993
+#define WINDOW_IS_VISIBLE 9995
+#define WINDOW_NEXT 9996
+#define WINDOW_PREVIOUS 9997
+#define WINDOW_IS_MEDIA 9998
+#define WINDOW_IS_ACTIVE 9999
+#define WINDOW_IS 10000
+#define WINDOW_IS_DIALOG_TOPMOST 10001
+#define WINDOW_IS_MODAL_DIALOG_TOPMOST 10002
+
+#define CONTROL_GET_LABEL 29996
+#define CONTROL_IS_ENABLED 29997
+#define CONTROL_IS_VISIBLE 29998
+#define CONTROL_GROUP_HAS_FOCUS 29999
+#define CONTROL_HAS_FOCUS 30000
+
+#define LISTITEM_START 35000
+#define LISTITEM_THUMB (LISTITEM_START)
+#define LISTITEM_LABEL (LISTITEM_START + 1)
+#define LISTITEM_TITLE (LISTITEM_START + 2)
+#define LISTITEM_TRACKNUMBER (LISTITEM_START + 3)
+#define LISTITEM_ARTIST (LISTITEM_START + 4)
+#define LISTITEM_ALBUM (LISTITEM_START + 5)
+#define LISTITEM_YEAR (LISTITEM_START + 6)
+#define LISTITEM_GENRE (LISTITEM_START + 7)
+#define LISTITEM_ICON (LISTITEM_START + 8)
+#define LISTITEM_DIRECTOR (LISTITEM_START + 9)
+#define LISTITEM_OVERLAY (LISTITEM_START + 10)
+#define LISTITEM_LABEL2 (LISTITEM_START + 11)
+#define LISTITEM_FILENAME (LISTITEM_START + 12)
+#define LISTITEM_DATE (LISTITEM_START + 13)
+#define LISTITEM_SIZE (LISTITEM_START + 14)
+#define LISTITEM_RATING (LISTITEM_START + 15)
+#define LISTITEM_PROGRAM_COUNT (LISTITEM_START + 16)
+#define LISTITEM_DURATION (LISTITEM_START + 17)
+#define LISTITEM_ISPLAYING (LISTITEM_START + 18)
+#define LISTITEM_ISSELECTED (LISTITEM_START + 19)
+#define LISTITEM_PLOT (LISTITEM_START + 20)
+#define LISTITEM_PLOT_OUTLINE (LISTITEM_START + 21)
+#define LISTITEM_EPISODE (LISTITEM_START + 22)
+#define LISTITEM_SEASON (LISTITEM_START + 23)
+#define LISTITEM_TVSHOW (LISTITEM_START + 24)
+#define LISTITEM_PREMIERED (LISTITEM_START + 25)
+#define LISTITEM_COMMENT (LISTITEM_START + 26)
+#define LISTITEM_ACTUAL_ICON (LISTITEM_START + 27)
+#define LISTITEM_PATH (LISTITEM_START + 28)
+#define LISTITEM_PICTURE_PATH (LISTITEM_START + 29)
+
+#define LISTITEM_PICTURE_START (LISTITEM_START + 30)
+#define LISTITEM_PICTURE_RESOLUTION (LISTITEM_PICTURE_START) // => SLIDESHOW_RESOLUTION
+#define LISTITEM_PICTURE_LONGDATE (LISTITEM_START + 31) // => SLIDESHOW_EXIF_LONG_DATE
+#define LISTITEM_PICTURE_LONGDATETIME (LISTITEM_START + 32) // => SLIDESHOW_EXIF_LONG_DATE_TIME
+#define LISTITEM_PICTURE_DATE (LISTITEM_START + 33) // => SLIDESHOW_EXIF_DATE
+#define LISTITEM_PICTURE_DATETIME (LISTITEM_START + 34) // => SLIDESHOW_EXIF_DATE_TIME
+#define LISTITEM_PICTURE_COMMENT (LISTITEM_START + 35) // => SLIDESHOW_COMMENT
+#define LISTITEM_PICTURE_CAPTION (LISTITEM_START + 36) // => SLIDESHOW_IPTC_CAPTION
+#define LISTITEM_PICTURE_DESC (LISTITEM_START + 37) // => SLIDESHOW_EXIF_DESCRIPTION
+#define LISTITEM_PICTURE_KEYWORDS (LISTITEM_START + 38) // => SLIDESHOW_IPTC_KEYWORDS
+#define LISTITEM_PICTURE_CAM_MAKE (LISTITEM_START + 39) // => SLIDESHOW_EXIF_CAMERA_MAKE
+#define LISTITEM_PICTURE_CAM_MODEL (LISTITEM_START + 40) // => SLIDESHOW_EXIF_CAMERA_MODEL
+#define LISTITEM_PICTURE_APERTURE (LISTITEM_START + 41) // => SLIDESHOW_EXIF_APERTURE
+#define LISTITEM_PICTURE_FOCAL_LEN (LISTITEM_START + 42) // => SLIDESHOW_EXIF_FOCAL_LENGTH
+#define LISTITEM_PICTURE_FOCUS_DIST (LISTITEM_START + 43) // => SLIDESHOW_EXIF_FOCUS_DIST
+#define LISTITEM_PICTURE_EXP_MODE (LISTITEM_START + 44) // => SLIDESHOW_EXIF_EXPOSURE_MODE
+#define LISTITEM_PICTURE_EXP_TIME (LISTITEM_START + 45) // => SLIDESHOW_EXIF_EXPOSURE_TIME
+#define LISTITEM_PICTURE_ISO (LISTITEM_START + 46) // => SLIDESHOW_EXIF_ISO_EQUIV
+#define LISTITEM_PICTURE_AUTHOR (LISTITEM_START + 47) // => SLIDESHOW_IPTC_AUTHOR
+#define LISTITEM_PICTURE_BYLINE (LISTITEM_START + 48) // => SLIDESHOW_IPTC_BYLINE
+#define LISTITEM_PICTURE_BYLINE_TITLE (LISTITEM_START + 49) // => SLIDESHOW_IPTC_BYLINE_TITLE
+#define LISTITEM_PICTURE_CATEGORY (LISTITEM_START + 50) // => SLIDESHOW_IPTC_CATEGORY
+#define LISTITEM_PICTURE_CCD_WIDTH (LISTITEM_START + 51) // => SLIDESHOW_EXIF_CCD_WIDTH
+#define LISTITEM_PICTURE_CITY (LISTITEM_START + 52) // => SLIDESHOW_IPTC_CITY
+#define LISTITEM_PICTURE_URGENCY (LISTITEM_START + 53) // => SLIDESHOW_IPTC_URGENCY
+#define LISTITEM_PICTURE_COPYRIGHT_NOTICE (LISTITEM_START + 54) // => SLIDESHOW_IPTC_COPYRIGHT_NOTICE
+#define LISTITEM_PICTURE_COUNTRY (LISTITEM_START + 55) // => SLIDESHOW_IPTC_COUNTRY
+#define LISTITEM_PICTURE_COUNTRY_CODE (LISTITEM_START + 56) // => SLIDESHOW_IPTC_COUNTRY_CODE
+#define LISTITEM_PICTURE_CREDIT (LISTITEM_START + 57) // => SLIDESHOW_IPTC_CREDIT
+#define LISTITEM_PICTURE_IPTCDATE (LISTITEM_START + 58) // => SLIDESHOW_IPTC_DATE
+#define LISTITEM_PICTURE_DIGITAL_ZOOM (LISTITEM_START + 59) // => SLIDESHOW_EXIF_DIGITAL_ZOOM
+#define LISTITEM_PICTURE_EXPOSURE (LISTITEM_START + 60) // => SLIDESHOW_EXIF_EXPOSURE
+#define LISTITEM_PICTURE_EXPOSURE_BIAS (LISTITEM_START + 61) // => SLIDESHOW_EXIF_EXPOSURE_BIAS
+#define LISTITEM_PICTURE_FLASH_USED (LISTITEM_START + 62) // => SLIDESHOW_EXIF_FLASH_USED
+#define LISTITEM_PICTURE_HEADLINE (LISTITEM_START + 63) // => SLIDESHOW_IPTC_HEADLINE
+#define LISTITEM_PICTURE_COLOUR (LISTITEM_START + 64) // => SLIDESHOW_COLOUR
+#define LISTITEM_PICTURE_LIGHT_SOURCE (LISTITEM_START + 65) // => SLIDESHOW_EXIF_LIGHT_SOURCE
+#define LISTITEM_PICTURE_METERING_MODE (LISTITEM_START + 66) // => SLIDESHOW_EXIF_METERING_MODE
+#define LISTITEM_PICTURE_OBJECT_NAME (LISTITEM_START + 67) // => SLIDESHOW_IPTC_OBJECT_NAME
+#define LISTITEM_PICTURE_ORIENTATION (LISTITEM_START + 68) // => SLIDESHOW_EXIF_ORIENTATION
+#define LISTITEM_PICTURE_PROCESS (LISTITEM_START + 69) // => SLIDESHOW_PROCESS
+#define LISTITEM_PICTURE_REF_SERVICE (LISTITEM_START + 70) // => SLIDESHOW_IPTC_REF_SERVICE
+#define LISTITEM_PICTURE_SOURCE (LISTITEM_START + 71) // => SLIDESHOW_IPTC_SOURCE
+#define LISTITEM_PICTURE_SPEC_INSTR (LISTITEM_START + 72) // => SLIDESHOW_IPTC_SPEC_INSTR
+#define LISTITEM_PICTURE_STATE (LISTITEM_START + 73) // => SLIDESHOW_IPTC_STATE
+#define LISTITEM_PICTURE_SUP_CATEGORIES (LISTITEM_START + 74) // => SLIDESHOW_IPTC_SUP_CATEGORIES
+#define LISTITEM_PICTURE_TX_REFERENCE (LISTITEM_START + 75) // => SLIDESHOW_IPTC_TX_REFERENCE
+#define LISTITEM_PICTURE_WHITE_BALANCE (LISTITEM_START + 76) // => SLIDESHOW_EXIF_WHITE_BALANCE
+#define LISTITEM_PICTURE_IMAGETYPE (LISTITEM_START + 77) // => SLIDESHOW_IPTC_IMAGETYPE
+#define LISTITEM_PICTURE_SUBLOCATION (LISTITEM_START + 78) // => SLIDESHOW_IPTC_SUBLOCATION
+#define LISTITEM_PICTURE_TIMECREATED (LISTITEM_START + 79) // => SLIDESHOW_IPTC_TIMECREATED
+#define LISTITEM_PICTURE_GPS_LAT (LISTITEM_START + 80) // => SLIDESHOW_EXIF_GPS_LATITUDE
+#define LISTITEM_PICTURE_GPS_LON (LISTITEM_START + 81) // => SLIDESHOW_EXIF_GPS_LONGITUDE
+#define LISTITEM_PICTURE_GPS_ALT (LISTITEM_START + 82) // => SLIDESHOW_EXIF_GPS_ALTITUDE
+#define LISTITEM_PICTURE_END (LISTITEM_PICTURE_GPS_ALT)
+
+#define LISTITEM_STUDIO (LISTITEM_START + 83)
+#define LISTITEM_MPAA (LISTITEM_START + 84)
+#define LISTITEM_CAST (LISTITEM_START + 85)
+#define LISTITEM_CAST_AND_ROLE (LISTITEM_START + 86)
+#define LISTITEM_WRITER (LISTITEM_START + 87)
+#define LISTITEM_TAGLINE (LISTITEM_START + 88)
+#define LISTITEM_TOP250 (LISTITEM_START + 89)
+#define LISTITEM_RATING_AND_VOTES (LISTITEM_START + 90)
+#define LISTITEM_TRAILER (LISTITEM_START + 91)
+#define LISTITEM_APPEARANCES (LISTITEM_START + 92)
+#define LISTITEM_FILENAME_AND_PATH (LISTITEM_START + 93)
+#define LISTITEM_SORT_LETTER (LISTITEM_START + 94)
+#define LISTITEM_ALBUM_ARTIST (LISTITEM_START + 95)
+#define LISTITEM_FOLDERNAME (LISTITEM_START + 96)
+#define LISTITEM_VIDEO_CODEC (LISTITEM_START + 97)
+#define LISTITEM_VIDEO_RESOLUTION (LISTITEM_START + 98)
+#define LISTITEM_VIDEO_ASPECT (LISTITEM_START + 99)
+#define LISTITEM_AUDIO_CODEC (LISTITEM_START + 100)
+#define LISTITEM_AUDIO_CHANNELS (LISTITEM_START + 101)
+#define LISTITEM_AUDIO_LANGUAGE (LISTITEM_START + 102)
+#define LISTITEM_SUBTITLE_LANGUAGE (LISTITEM_START + 103)
+#define LISTITEM_IS_FOLDER (LISTITEM_START + 104)
+#define LISTITEM_ORIGINALTITLE (LISTITEM_START + 105)
+#define LISTITEM_COUNTRY (LISTITEM_START + 106)
+#define LISTITEM_PLAYCOUNT (LISTITEM_START + 107)
+#define LISTITEM_LASTPLAYED (LISTITEM_START + 108)
+#define LISTITEM_FOLDERPATH (LISTITEM_START + 109)
+#define LISTITEM_DISC_NUMBER (LISTITEM_START + 110)
+#define LISTITEM_FILE_EXTENSION (LISTITEM_START + 111)
+#define LISTITEM_IS_RESUMABLE (LISTITEM_START + 112)
+#define LISTITEM_PERCENT_PLAYED (LISTITEM_START + 113)
+#define LISTITEM_DATE_ADDED (LISTITEM_START + 114)
+#define LISTITEM_DBTYPE (LISTITEM_START + 115)
+#define LISTITEM_DBID (LISTITEM_START + 116)
+#define LISTITEM_ART (LISTITEM_START + 117)
+#define LISTITEM_STARTTIME (LISTITEM_START + 118)
+#define LISTITEM_ENDTIME (LISTITEM_START + 119)
+#define LISTITEM_STARTDATE (LISTITEM_START + 120)
+#define LISTITEM_ENDDATE (LISTITEM_START + 121)
+#define LISTITEM_NEXT_TITLE (LISTITEM_START + 122)
+#define LISTITEM_NEXT_GENRE (LISTITEM_START + 123)
+#define LISTITEM_NEXT_PLOT (LISTITEM_START + 124)
+#define LISTITEM_NEXT_PLOT_OUTLINE (LISTITEM_START + 125)
+#define LISTITEM_NEXT_STARTTIME (LISTITEM_START + 126)
+#define LISTITEM_NEXT_ENDTIME (LISTITEM_START + 127)
+#define LISTITEM_NEXT_STARTDATE (LISTITEM_START + 128)
+#define LISTITEM_NEXT_ENDDATE (LISTITEM_START + 129)
+#define LISTITEM_NEXT_DURATION (LISTITEM_START + 130)
+#define LISTITEM_CHANNEL_NAME (LISTITEM_START + 131)
+#define LISTITEM_CHANNEL_GROUP (LISTITEM_START + 132)
+#define LISTITEM_HASTIMER (LISTITEM_START + 133)
+#define LISTITEM_ISRECORDING (LISTITEM_START + 134)
+#define LISTITEM_ISENCRYPTED (LISTITEM_START + 135)
+#define LISTITEM_PARENTAL_RATING (LISTITEM_START + 136)
+#define LISTITEM_PROGRESS (LISTITEM_START + 137)
+#define LISTITEM_HAS_EPG (LISTITEM_START + 138)
+#define LISTITEM_VOTES (LISTITEM_START + 139)
+#define LISTITEM_STEREOSCOPIC_MODE (LISTITEM_START + 140)
+#define LISTITEM_IS_STEREOSCOPIC (LISTITEM_START + 141)
+#define LISTITEM_INPROGRESS (LISTITEM_START + 142)
+#define LISTITEM_HASRECORDING (LISTITEM_START + 143)
+#define LISTITEM_HASREMINDER (LISTITEM_START + 144)
+#define LISTITEM_CHANNEL_NUMBER (LISTITEM_START + 145)
+#define LISTITEM_IMDBNUMBER (LISTITEM_START + 146)
+#define LISTITEM_EPISODENAME (LISTITEM_START + 147)
+#define LISTITEM_IS_COLLECTION (LISTITEM_START + 148)
+#define LISTITEM_HASTIMERSCHEDULE (LISTITEM_START + 149)
+#define LISTITEM_TIMERTYPE (LISTITEM_START + 150)
+#define LISTITEM_EPG_EVENT_TITLE (LISTITEM_START + 151)
+#define LISTITEM_DATETIME (LISTITEM_START + 152)
+#define LISTITEM_USER_RATING (LISTITEM_START + 153)
+#define LISTITEM_TAG (LISTITEM_START + 154)
+#define LISTITEM_SET (LISTITEM_START + 155)
+#define LISTITEM_SETID (LISTITEM_START + 156)
+#define LISTITEM_IS_PARENTFOLDER (LISTITEM_START + 157)
+#define LISTITEM_MOOD (LISTITEM_START + 158)
+#define LISTITEM_CONTRIBUTORS (LISTITEM_START + 159)
+#define LISTITEM_CONTRIBUTOR_AND_ROLE (LISTITEM_START + 160)
+#define LISTITEM_TIMERISACTIVE (LISTITEM_START + 161)
+#define LISTITEM_TIMERHASCONFLICT (LISTITEM_START + 162)
+#define LISTITEM_TIMERHASERROR (LISTITEM_START + 163)
+
+#define LISTITEM_ADDON_NAME (LISTITEM_START + 164)
+#define LISTITEM_ADDON_VERSION (LISTITEM_START + 165)
+#define LISTITEM_ADDON_CREATOR (LISTITEM_START + 166)
+#define LISTITEM_ADDON_SUMMARY (LISTITEM_START + 167)
+#define LISTITEM_ADDON_DESCRIPTION (LISTITEM_START + 168)
+#define LISTITEM_ADDON_DISCLAIMER (LISTITEM_START + 169)
+#define LISTITEM_ADDON_BROKEN (LISTITEM_START + 170)
+#define LISTITEM_ADDON_LIFECYCLE_TYPE (LISTITEM_START + 171)
+#define LISTITEM_ADDON_LIFECYCLE_DESC (LISTITEM_START + 172)
+#define LISTITEM_ADDON_TYPE (LISTITEM_START + 173)
+#define LISTITEM_ADDON_INSTALL_DATE (LISTITEM_START + 174)
+#define LISTITEM_ADDON_LAST_UPDATED (LISTITEM_START + 175)
+#define LISTITEM_ADDON_LAST_USED (LISTITEM_START + 176)
+#define LISTITEM_STATUS (LISTITEM_START + 177)
+#define LISTITEM_ENDTIME_RESUME (LISTITEM_START + 178)
+#define LISTITEM_ADDON_ORIGIN (LISTITEM_START + 179)
+#define LISTITEM_ADDON_NEWS (LISTITEM_START + 180)
+#define LISTITEM_ADDON_SIZE (LISTITEM_START + 181)
+#define LISTITEM_EXPIRATION_DATE (LISTITEM_START + 182)
+#define LISTITEM_EXPIRATION_TIME (LISTITEM_START + 183)
+#define LISTITEM_PROPERTY (LISTITEM_START + 184)
+#define LISTITEM_EPG_EVENT_ICON (LISTITEM_START + 185)
+#define LISTITEM_HASREMINDERRULE (LISTITEM_START + 186)
+#define LISTITEM_HASARCHIVE (LISTITEM_START + 187)
+#define LISTITEM_ISPLAYABLE (LISTITEM_START + 188)
+#define LISTITEM_FILENAME_NO_EXTENSION (LISTITEM_START + 189)
+#define LISTITEM_CURRENTITEM (LISTITEM_START + 190)
+#define LISTITEM_IS_NEW (LISTITEM_START + 191)
+#define LISTITEM_DISC_TITLE (LISTITEM_START + 192)
+#define LISTITEM_IS_BOXSET (LISTITEM_START + 193)
+#define LISTITEM_TOTALDISCS (LISTITEM_START + 194)
+#define LISTITEM_RELEASEDATE (LISTITEM_START + 195)
+#define LISTITEM_ORIGINALDATE (LISTITEM_START + 196)
+#define LISTITEM_BPM (LISTITEM_START + 197)
+#define LISTITEM_UNIQUEID (LISTITEM_START + 198)
+#define LISTITEM_BITRATE (LISTITEM_START + 199)
+#define LISTITEM_SAMPLERATE (LISTITEM_START + 200)
+#define LISTITEM_MUSICCHANNELS (LISTITEM_START + 201)
+#define LISTITEM_IS_PREMIERE (LISTITEM_START + 202)
+#define LISTITEM_IS_FINALE (LISTITEM_START + 203)
+#define LISTITEM_IS_LIVE (LISTITEM_START + 204)
+#define LISTITEM_TVSHOWDBID (LISTITEM_START + 205)
+#define LISTITEM_ALBUMSTATUS (LISTITEM_START + 206)
+#define LISTITEM_ISAUTOUPDATEABLE (LISTITEM_START + 207)
+#define LISTITEM_VIDEO_HDR_TYPE (LISTITEM_START + 208)
+
+#define LISTITEM_END (LISTITEM_START + 2500)
+
+#define CONDITIONAL_LABEL_START (LISTITEM_END + 1) // 37501
+#define CONDITIONAL_LABEL_END 39999
+
+// the multiple information vector
+#define MULTI_INFO_START 40000
+#define MULTI_INFO_END 99999
+#define COMBINED_VALUES_START 100000
+
+// listitem info Flags
+// Stored in the top 8 bits of GUIInfo::m_data1
+// therefore we only have room for 8 flags
+#define INFOFLAG_LISTITEM_WRAP (static_cast<uint32_t>(1 << 25)) // Wrap ListItem lookups
+#define INFOFLAG_LISTITEM_POSITION (static_cast<uint32_t>(1 << 26)) // ListItem lookups based on cursor position
+#define INFOFLAG_LISTITEM_ABSOLUTE (static_cast<uint32_t>(1 << 27)) // Absolute ListItem lookups
+#define INFOFLAG_LISTITEM_NOWRAP (static_cast<uint32_t>(1 << 28)) // Do not wrap ListItem lookups
+#define INFOFLAG_LISTITEM_CONTAINER (static_cast<uint32_t>(1 << 29)) // Lookup the item in given container
+// clang-format on
diff --git a/xbmc/guilib/guiinfo/GUIInfoProvider.h b/xbmc/guilib/guiinfo/GUIInfoProvider.h
new file mode 100644
index 0000000..a03159b
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoProvider.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "cores/VideoPlayer/Interface/StreamInfo.h"
+#include "guilib/guiinfo/IGUIInfoProvider.h"
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CGUIInfoProvider : public IGUIInfoProvider
+{
+public:
+ CGUIInfoProvider() = default;
+ ~CGUIInfoProvider() override = default;
+
+ bool GetFallbackLabel(std::string& value,
+ const CFileItem* item,
+ int contextWindow,
+ const CGUIInfo& info,
+ std::string* fallback) override
+ {
+ return false;
+ }
+
+ void UpdateAVInfo(const AudioStreamInfo& audioInfo, const VideoStreamInfo& videoInfo, const SubtitleStreamInfo& subtitleInfo) override
+ { m_audioInfo = audioInfo, m_videoInfo = videoInfo, m_subtitleInfo = subtitleInfo; }
+
+protected:
+ VideoStreamInfo m_videoInfo;
+ AudioStreamInfo m_audioInfo;
+ SubtitleStreamInfo m_subtitleInfo;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/GUIInfoProviders.cpp b/xbmc/guilib/guiinfo/GUIInfoProviders.cpp
new file mode 100644
index 0000000..274318e
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoProviders.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/GUIInfoProviders.h"
+
+#include "guilib/guiinfo/IGUIInfoProvider.h"
+
+#include <algorithm>
+
+using namespace KODI::GUILIB::GUIINFO;
+
+CGUIInfoProviders::CGUIInfoProviders()
+{
+ RegisterProvider(&m_guiControlsGUIInfo);
+ RegisterProvider(&m_videoGUIInfo); // Note: video info provider must be registered before music info provider,
+ // because of music videos having both a video info tag and a music info tag
+ // and video info tag always has to be evaluated first.
+ RegisterProvider(&m_musicGUIInfo);
+ RegisterProvider(&m_picturesGUIInfo);
+ RegisterProvider(&m_playerGUIInfo);
+ RegisterProvider(&m_libraryGUIInfo);
+ RegisterProvider(&m_addonsGUIInfo);
+ RegisterProvider(&m_weatherGUIInfo);
+ RegisterProvider(&m_gamesGUIInfo);
+ RegisterProvider(&m_systemGUIInfo);
+ RegisterProvider(&m_visualisationGUIInfo);
+ RegisterProvider(&m_skinGUIInfo);
+}
+
+CGUIInfoProviders::~CGUIInfoProviders()
+{
+ UnregisterProvider(&m_skinGUIInfo);
+ UnregisterProvider(&m_visualisationGUIInfo);
+ UnregisterProvider(&m_systemGUIInfo);
+ UnregisterProvider(&m_gamesGUIInfo);
+ UnregisterProvider(&m_weatherGUIInfo);
+ UnregisterProvider(&m_addonsGUIInfo);
+ UnregisterProvider(&m_libraryGUIInfo);
+ UnregisterProvider(&m_playerGUIInfo);
+ UnregisterProvider(&m_picturesGUIInfo);
+ UnregisterProvider(&m_musicGUIInfo);
+ UnregisterProvider(&m_videoGUIInfo);
+ UnregisterProvider(&m_guiControlsGUIInfo);
+}
+
+void CGUIInfoProviders::RegisterProvider(IGUIInfoProvider *provider, bool bAppend /* = true */)
+{
+ auto it = std::find(m_providers.begin(), m_providers.end(), provider);
+ if (it == m_providers.end())
+ {
+ if (bAppend)
+ m_providers.emplace_back(provider);
+ else
+ m_providers.insert(m_providers.begin(), provider);
+ }
+}
+
+void CGUIInfoProviders::UnregisterProvider(IGUIInfoProvider *provider)
+{
+ auto it = std::find(m_providers.begin(), m_providers.end(), provider);
+ if (it != m_providers.end())
+ m_providers.erase(it);
+}
+
+bool CGUIInfoProviders::InitCurrentItem(CFileItem *item)
+{
+ bool bReturn = false;
+
+ for (const auto& provider : m_providers)
+ {
+ bReturn = provider->InitCurrentItem(item);
+ }
+ return bReturn;
+}
+
+bool CGUIInfoProviders::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ for (const auto& provider : m_providers)
+ {
+ if (provider->GetLabel(value, item, contextWindow, info, fallback))
+ return true;
+ }
+ for (const auto& provider : m_providers)
+ {
+ if (provider->GetFallbackLabel(value, item, contextWindow, info, fallback))
+ return true;
+ }
+ return false;
+}
+
+bool CGUIInfoProviders::GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const
+{
+ for (const auto& provider : m_providers)
+ {
+ if (provider->GetInt(value, item, contextWindow, info))
+ return true;
+ }
+ return false;
+}
+
+bool CGUIInfoProviders::GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const
+{
+ for (const auto& provider : m_providers)
+ {
+ if (provider->GetBool(value, item, contextWindow, info))
+ return true;
+ }
+ return false;
+}
+
+void CGUIInfoProviders::UpdateAVInfo(const AudioStreamInfo& audioInfo, const VideoStreamInfo& videoInfo, const SubtitleStreamInfo& subtitleInfo)
+{
+ for (const auto& provider : m_providers)
+ {
+ provider->UpdateAVInfo(audioInfo, videoInfo, subtitleInfo);
+ }
+}
diff --git a/xbmc/guilib/guiinfo/GUIInfoProviders.h b/xbmc/guilib/guiinfo/GUIInfoProviders.h
new file mode 100644
index 0000000..1aed710
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GUIInfoProviders.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/AddonsGUIInfo.h"
+#include "guilib/guiinfo/GUIControlsGUIInfo.h"
+#include "guilib/guiinfo/GamesGUIInfo.h"
+#include "guilib/guiinfo/LibraryGUIInfo.h"
+#include "guilib/guiinfo/MusicGUIInfo.h"
+#include "guilib/guiinfo/PicturesGUIInfo.h"
+#include "guilib/guiinfo/PlayerGUIInfo.h"
+#include "guilib/guiinfo/SkinGUIInfo.h"
+#include "guilib/guiinfo/SystemGUIInfo.h"
+#include "guilib/guiinfo/VideoGUIInfo.h"
+#include "guilib/guiinfo/VisualisationGUIInfo.h"
+#include "guilib/guiinfo/WeatherGUIInfo.h"
+
+#include <string>
+#include <vector>
+
+class CFileItem;
+class CGUIListItem;
+
+struct AudioStreamInfo;
+struct VideoStreamInfo;
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+class IGUIInfoProvider;
+
+class CGUIInfoProviders
+{
+public:
+ CGUIInfoProviders();
+ virtual ~CGUIInfoProviders();
+
+ /*!
+ * @brief Register a guiinfo provider.
+ * @param provider The provider to register.
+ * @param bAppend True to append to the list of providers, false to insert before the first provider
+ */
+ void RegisterProvider(IGUIInfoProvider *provider, bool bAppend = true);
+
+ /*!
+ * @brief Unregister a guiinfo provider.
+ * @param provider The provider to unregister.
+ */
+ void UnregisterProvider(IGUIInfoProvider *provider);
+
+ /*!
+ * @brief Init a new current guiinfo manager item. Gets called whenever the active guiinfo manager item changes.
+ * @param item The new item.
+ * @return True if the item was inited by one of the providers, false otherwise.
+ */
+ bool InitCurrentItem(CFileItem *item);
+
+ /*!
+ * @brief Get a GUIInfoManager label string from one of the registered providers.
+ * @param value Will be filled with the requested value.
+ * @param item The item to get the value for. Can be nullptr.
+ * @param contextWindow The context window. Can be 0.
+ * @param info The GUI info (label id + additional data).
+ * @param fallback A fallback value. Can be nullptr.
+ * @return True if the value was filled successfully by one of the providers, false otherwise.
+ */
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const;
+
+ /*!
+ * @brief Get a GUIInfoManager integer value from one of the registered providers.
+ * @param value Will be filled with the requested value.
+ * @param item The item to get the value for. Can be nullptr.
+ * @param contextWindow The context window. Can be 0.
+ * @param info The GUI info (label id + additional data).
+ * @return True if the value was filled successfully by one of the providers, false otherwise.
+ */
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const;
+
+ /*!
+ * @brief Get a GUIInfoManager bool value from one of the registered providers.
+ * @param value Will be filled with the requested value.
+ * @param item The item to get the value for. Can be nullptr.
+ * @param contextWindow The context window. Can be 0.
+ * @param info The GUI info (label id + additional data).
+ * @return True if the value was filled successfully by one of the providers, false otherwise.
+ */
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const;
+
+ /*!
+ * @brief Set new audio/video/subtitle stream info data at all registered providers.
+ * @param audioInfo New audio stream info.
+ * @param videoInfo New video stream info.
+ * @param subtitleInfo New subtitle stream info.
+ */
+ void UpdateAVInfo(const AudioStreamInfo& audioInfo, const VideoStreamInfo& videoInfo, const SubtitleStreamInfo& subtitleInfo);
+
+ /*!
+ * @brief Get the player guiinfo provider.
+ * @return The player guiinfo provider.
+ */
+ CPlayerGUIInfo& GetPlayerInfoProvider() { return m_playerGUIInfo; }
+
+ /*!
+ * @brief Get the system guiinfo provider.
+ * @return The system guiinfo provider.
+ */
+ CSystemGUIInfo& GetSystemInfoProvider() { return m_systemGUIInfo; }
+
+ /*!
+ * @brief Get the pictures guiinfo provider.
+ * @return The pictures guiinfo provider.
+ */
+ CPicturesGUIInfo& GetPicturesInfoProvider() { return m_picturesGUIInfo; }
+
+ /*!
+ * @brief Get the gui controls guiinfo provider.
+ * @return The gui controls guiinfo provider.
+ */
+ CGUIControlsGUIInfo& GetGUIControlsInfoProvider() { return m_guiControlsGUIInfo; }
+
+ /*!
+ * @brief Get the library guiinfo provider.
+ * @return The library guiinfo provider.
+ */
+ CLibraryGUIInfo& GetLibraryInfoProvider() { return m_libraryGUIInfo; }
+
+private:
+ std::vector<IGUIInfoProvider *> m_providers;
+
+ CAddonsGUIInfo m_addonsGUIInfo;
+ CGamesGUIInfo m_gamesGUIInfo;
+ CGUIControlsGUIInfo m_guiControlsGUIInfo;
+ CLibraryGUIInfo m_libraryGUIInfo;
+ CMusicGUIInfo m_musicGUIInfo;
+ CPicturesGUIInfo m_picturesGUIInfo;
+ CPlayerGUIInfo m_playerGUIInfo;
+ CSkinGUIInfo m_skinGUIInfo;
+ CSystemGUIInfo m_systemGUIInfo;
+ CVideoGUIInfo m_videoGUIInfo;
+ CVisualisationGUIInfo m_visualisationGUIInfo;
+ CWeatherGUIInfo m_weatherGUIInfo;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/GamesGUIInfo.cpp b/xbmc/guilib/guiinfo/GamesGUIInfo.cpp
new file mode 100644
index 0000000..5428c3a
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GamesGUIInfo.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/GamesGUIInfo.h"
+
+#include "FileItem.h"
+#include "Util.h"
+#include "cores/RetroPlayer/RetroPlayerUtils.h"
+#include "games/tags/GameInfoTag.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "settings/MediaSettings.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
+
+using namespace KODI::GUILIB::GUIINFO;
+using namespace KODI::GAME;
+using namespace KODI::RETRO;
+
+//! @todo Savestates were removed from v18
+//#define FILEITEM_PROPERTY_SAVESTATE_DURATION "duration"
+
+bool CGamesGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ if (item && item->IsGame())
+ {
+ CLog::Log(LOGDEBUG, "CGamesGUIInfo::InitCurrentItem({})", item->GetPath());
+
+ item->LoadGameTag();
+ CGameInfoTag* tag = item->GetGameInfoTag(); // creates item if not yet set, so no nullptr checks needed
+
+ if (tag->GetTitle().empty())
+ {
+ // No title in tag, show filename only
+ tag->SetTitle(CUtil::GetTitleFromPath(item->GetPath()));
+ }
+ return true;
+ }
+ return false;
+}
+
+bool CGamesGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // RETROPLAYER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case RETROPLAYER_VIDEO_FILTER:
+ {
+ value = CMediaSettings::GetInstance().GetCurrentGameSettings().VideoFilter();
+ return true;
+ }
+ case RETROPLAYER_STRETCH_MODE:
+ {
+ STRETCHMODE stretchMode = CMediaSettings::GetInstance().GetCurrentGameSettings().StretchMode();
+ value = CRetroPlayerUtils::StretchModeToIdentifier(stretchMode);
+ return true;
+ }
+ case RETROPLAYER_VIDEO_ROTATION:
+ {
+ const unsigned int rotationDegCCW = CMediaSettings::GetInstance().GetCurrentGameSettings().RotationDegCCW();
+ value = std::to_string(rotationDegCCW);
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool CGamesGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ return false;
+}
+
+bool CGamesGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/GamesGUIInfo.h b/xbmc/guilib/guiinfo/GamesGUIInfo.h
new file mode 100644
index 0000000..5ad78d9
--- /dev/null
+++ b/xbmc/guilib/guiinfo/GamesGUIInfo.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CGamesGUIInfo : public CGUIInfoProvider
+{
+public:
+ CGamesGUIInfo() = default;
+ ~CGamesGUIInfo() override = default;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/IGUIInfoProvider.h b/xbmc/guilib/guiinfo/IGUIInfoProvider.h
new file mode 100644
index 0000000..4560b08
--- /dev/null
+++ b/xbmc/guilib/guiinfo/IGUIInfoProvider.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+class CFileItem;
+class CGUIListItem;
+
+struct AudioStreamInfo;
+struct VideoStreamInfo;
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class IGUIInfoProvider
+{
+public:
+ virtual ~IGUIInfoProvider() = default;
+
+ /*!
+ * @brief Init a new current guiinfo manager item. Gets called whenever the active guiinfo manager item changes.
+ * @param item The new item.
+ * @return True if the item was inited by the provider, false otherwise.
+ */
+ virtual bool InitCurrentItem(CFileItem *item) = 0;
+
+ /*!
+ * @brief Get a GUIInfoManager label string.
+ * @param value Will be filled with the requested value.
+ * @param item The item to get the value for. Can be nullptr.
+ * @param contextWindow The context window. Can be 0.
+ * @param info The GUI info (label id + additional data).
+ * @param fallback A fallback value. Can be nullptr.
+ * @return True if the value was filled successfully, false otherwise.
+ */
+ virtual bool GetLabel(std::string &value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const = 0;
+
+ /*!
+ * @brief Get a GUIInfoManager label fallback string. Will be called if none of the registered
+ * provider's GetLabel() implementation has returned success.
+ * @param value Will be filled with the requested value.
+ * @param item The item to get the value for. Can be nullptr.
+ * @param contextWindow The context window. Can be 0.
+ * @param info The GUI info (label id + additional data).
+ * @param fallback A fallback value. Can be nullptr.
+ * @return True if the value was filled successfully, false otherwise.
+ */
+ virtual bool GetFallbackLabel(std::string& value,
+ const CFileItem* item,
+ int contextWindow,
+ const CGUIInfo& info,
+ std::string* fallback) = 0;
+
+ /*!
+ * @brief Get a GUIInfoManager integer value.
+ * @param value Will be filled with the requested value.
+ * @param item The item to get the value for. Can be nullptr.
+ * @param contextWindow The context window. Can be 0.
+ * @param info The GUI info (label id + additional data).
+ * @return True if the value was filled successfully, false otherwise.
+ */
+ virtual bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const = 0;
+
+ /*!
+ * @brief Get a GUIInfoManager bool value.
+ * @param value Will be filled with the requested value.
+ * @param item The item to get the value for. Can be nullptr.
+ * @param contextWindow The context window. Can be 0.
+ * @param info The GUI info (label id + additional data).
+ * @return True if the value was filled successfully, false otherwise.
+ */
+ virtual bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const = 0;
+
+ /*!
+ * @brief Set new audio/video stream info data.
+ * @param audioInfo New audio stream info.
+ * @param videoInfo New video stream info.
+ */
+ virtual void UpdateAVInfo(const AudioStreamInfo& audioInfo, const VideoStreamInfo& videoInfo, const SubtitleStreamInfo& subtitleInfo) = 0;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/LibraryGUIInfo.cpp b/xbmc/guilib/guiinfo/LibraryGUIInfo.cpp
new file mode 100644
index 0000000..fc0f471
--- /dev/null
+++ b/xbmc/guilib/guiinfo/LibraryGUIInfo.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/LibraryGUIInfo.h"
+
+#include "FileItem.h"
+#include "ServiceBroker.h"
+#include "URL.h"
+#include "filesystem/Directory.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "music/MusicDatabase.h"
+#include "music/MusicLibraryQueue.h"
+#include "profiles/ProfileManager.h"
+#include "settings/SettingsComponent.h"
+#include "utils/FileUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+#include "video/VideoDatabase.h"
+#include "video/VideoLibraryQueue.h"
+
+using namespace KODI::GUILIB::GUIINFO;
+
+CLibraryGUIInfo::CLibraryGUIInfo()
+{
+ ResetLibraryBools();
+}
+
+bool CLibraryGUIInfo::GetLibraryBool(int condition) const
+{
+ bool value = false;
+ GetBool(value, nullptr, 0, CGUIInfo(condition));
+ return value;
+}
+
+void CLibraryGUIInfo::SetLibraryBool(int condition, bool value)
+{
+ switch (condition)
+ {
+ case LIBRARY_HAS_MUSIC:
+ m_libraryHasMusic = value ? 1 : 0;
+ break;
+ case LIBRARY_HAS_MOVIES:
+ m_libraryHasMovies = value ? 1 : 0;
+ break;
+ case LIBRARY_HAS_MOVIE_SETS:
+ m_libraryHasMovieSets = value ? 1 : 0;
+ break;
+ case LIBRARY_HAS_TVSHOWS:
+ m_libraryHasTVShows = value ? 1 : 0;
+ break;
+ case LIBRARY_HAS_MUSICVIDEOS:
+ m_libraryHasMusicVideos = value ? 1 : 0;
+ break;
+ case LIBRARY_HAS_SINGLES:
+ m_libraryHasSingles = value ? 1 : 0;
+ break;
+ case LIBRARY_HAS_COMPILATIONS:
+ m_libraryHasCompilations = value ? 1 : 0;
+ break;
+ case LIBRARY_HAS_BOXSETS:
+ m_libraryHasBoxsets = value ? 1 : 0;
+ break;
+ default:
+ break;
+ }
+}
+
+void CLibraryGUIInfo::ResetLibraryBools()
+{
+ m_libraryHasMusic = -1;
+ m_libraryHasMovies = -1;
+ m_libraryHasTVShows = -1;
+ m_libraryHasMusicVideos = -1;
+ m_libraryHasMovieSets = -1;
+ m_libraryHasSingles = -1;
+ m_libraryHasCompilations = -1;
+ m_libraryHasBoxsets = -1;
+ m_libraryRoleCounts.clear();
+}
+
+bool CLibraryGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ return false;
+}
+
+bool CLibraryGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ return false;
+}
+
+bool CLibraryGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ return false;
+}
+
+bool CLibraryGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // LIBRARY_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case LIBRARY_HAS_MUSIC:
+ {
+ if (m_libraryHasMusic < 0)
+ { // query
+ CMusicDatabase db;
+ if (db.Open())
+ {
+ m_libraryHasMusic = (db.GetSongsCount() > 0) ? 1 : 0;
+ db.Close();
+ }
+ }
+ value = m_libraryHasMusic > 0;
+ return true;
+ }
+ case LIBRARY_HAS_MOVIES:
+ {
+ if (m_libraryHasMovies < 0)
+ {
+ CVideoDatabase db;
+ if (db.Open())
+ {
+ m_libraryHasMovies = db.HasContent(VideoDbContentType::MOVIES) ? 1 : 0;
+ db.Close();
+ }
+ }
+ value = m_libraryHasMovies > 0;
+ return true;
+ }
+ case LIBRARY_HAS_MOVIE_SETS:
+ {
+ if (m_libraryHasMovieSets < 0)
+ {
+ CVideoDatabase db;
+ if (db.Open())
+ {
+ m_libraryHasMovieSets = db.HasSets() ? 1 : 0;
+ db.Close();
+ }
+ }
+ value = m_libraryHasMovieSets > 0;
+ return true;
+ }
+ case LIBRARY_HAS_TVSHOWS:
+ {
+ if (m_libraryHasTVShows < 0)
+ {
+ CVideoDatabase db;
+ if (db.Open())
+ {
+ m_libraryHasTVShows = db.HasContent(VideoDbContentType::TVSHOWS) ? 1 : 0;
+ db.Close();
+ }
+ }
+ value = m_libraryHasTVShows > 0;
+ return true;
+ }
+ case LIBRARY_HAS_MUSICVIDEOS:
+ {
+ if (m_libraryHasMusicVideos < 0)
+ {
+ CVideoDatabase db;
+ if (db.Open())
+ {
+ m_libraryHasMusicVideos = db.HasContent(VideoDbContentType::MUSICVIDEOS) ? 1 : 0;
+ db.Close();
+ }
+ }
+ value = m_libraryHasMusicVideos > 0;
+ return true;
+ }
+ case LIBRARY_HAS_SINGLES:
+ {
+ if (m_libraryHasSingles < 0)
+ {
+ CMusicDatabase db;
+ if (db.Open())
+ {
+ m_libraryHasSingles = (db.GetSinglesCount() > 0) ? 1 : 0;
+ db.Close();
+ }
+ }
+ value = m_libraryHasSingles > 0;
+ return true;
+ }
+ case LIBRARY_HAS_COMPILATIONS:
+ {
+ if (m_libraryHasCompilations < 0)
+ {
+ CMusicDatabase db;
+ if (db.Open())
+ {
+ m_libraryHasCompilations = (db.GetCompilationAlbumsCount() > 0) ? 1 : 0;
+ db.Close();
+ }
+ }
+ value = m_libraryHasCompilations > 0;
+ return true;
+ }
+ case LIBRARY_HAS_BOXSETS:
+ {
+ if (m_libraryHasBoxsets < 0)
+ {
+ CMusicDatabase db;
+ if (db.Open())
+ {
+ m_libraryHasBoxsets = (db.GetBoxsetsCount() > 0) ? 1 : 0;
+ db.Close();
+ }
+ }
+ value = m_libraryHasBoxsets > 0;
+ return true;
+ }
+ case LIBRARY_HAS_VIDEO:
+ {
+ return (GetBool(value, gitem, contextWindow, CGUIInfo(LIBRARY_HAS_MOVIES)) ||
+ GetBool(value, gitem, contextWindow, CGUIInfo(LIBRARY_HAS_TVSHOWS)) ||
+ GetBool(value, gitem, contextWindow, CGUIInfo(LIBRARY_HAS_MUSICVIDEOS)));
+ }
+ case LIBRARY_HAS_ROLE:
+ {
+ std::string strRole = info.GetData3();
+ // Find value for role if already stored
+ int artistcount = -1;
+ for (const auto &role : m_libraryRoleCounts)
+ {
+ if (StringUtils::EqualsNoCase(strRole, role.first))
+ {
+ artistcount = role.second;
+ break;
+ }
+ }
+ // Otherwise get from DB and store
+ if (artistcount < 0)
+ {
+ CMusicDatabase db;
+ if (db.Open())
+ {
+ artistcount = db.GetArtistCountForRole(strRole);
+ db.Close();
+ m_libraryRoleCounts.emplace_back(std::make_pair(strRole, artistcount));
+ }
+ }
+ value = artistcount > 0;
+ return true;
+ }
+ case LIBRARY_HAS_NODE:
+ {
+ const CURL url(info.GetData3());
+ const std::shared_ptr<CProfileManager> profileManager =
+ CServiceBroker::GetSettingsComponent()->GetProfileManager();
+ CFileItemList items;
+
+ std::string libDir = profileManager->GetLibraryFolder();
+ XFILE::CDirectory::GetDirectory(libDir, items, "", XFILE::DIR_FLAG_NO_FILE_DIRS);
+ if (items.Size() == 0)
+ libDir = "special://xbmc/system/library/";
+
+ std::string nodePath = URIUtils::AddFileToFolder(libDir, url.GetHostName() + "/");
+ nodePath = URIUtils::AddFileToFolder(nodePath, url.GetFileName());
+ value = CFileUtils::Exists(nodePath);
+ return true;
+ }
+ case LIBRARY_IS_SCANNING:
+ {
+ value = (CMusicLibraryQueue::GetInstance().IsScanningLibrary() ||
+ CVideoLibraryQueue::GetInstance().IsScanningLibrary());
+ return true;
+ }
+ case LIBRARY_IS_SCANNING_VIDEO:
+ {
+ value = CVideoLibraryQueue::GetInstance().IsScanningLibrary();
+ return true;
+ }
+ case LIBRARY_IS_SCANNING_MUSIC:
+ {
+ value = CMusicLibraryQueue::GetInstance().IsScanningLibrary();
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/LibraryGUIInfo.h b/xbmc/guilib/guiinfo/LibraryGUIInfo.h
new file mode 100644
index 0000000..a9d47fc
--- /dev/null
+++ b/xbmc/guilib/guiinfo/LibraryGUIInfo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CLibraryGUIInfo : public CGUIInfoProvider
+{
+public:
+ CLibraryGUIInfo();
+ ~CLibraryGUIInfo() override = default;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+
+ bool GetLibraryBool(int condition) const;
+ void SetLibraryBool(int condition, bool value);
+ void ResetLibraryBools();
+
+private:
+ mutable int m_libraryHasMusic;
+ mutable int m_libraryHasMovies;
+ mutable int m_libraryHasTVShows;
+ mutable int m_libraryHasMusicVideos;
+ mutable int m_libraryHasMovieSets;
+ mutable int m_libraryHasSingles;
+ mutable int m_libraryHasCompilations;
+ mutable int m_libraryHasBoxsets;
+
+ //Count of artists in music library contributing to song by role e.g. composers, conductors etc.
+ //For checking visibility of custom nodes for a role.
+ mutable std::vector<std::pair<std::string, int>> m_libraryRoleCounts;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/MusicGUIInfo.cpp b/xbmc/guilib/guiinfo/MusicGUIInfo.cpp
new file mode 100644
index 0000000..f58a9ae
--- /dev/null
+++ b/xbmc/guilib/guiinfo/MusicGUIInfo.cpp
@@ -0,0 +1,713 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/MusicGUIInfo.h"
+
+#include "FileItem.h"
+#include "PartyModeManager.h"
+#include "PlayListPlayer.h"
+#include "ServiceBroker.h"
+#include "URL.h"
+#include "Util.h"
+#include "application/Application.h"
+#include "application/ApplicationComponents.h"
+#include "application/ApplicationPlayer.h"
+#include "guilib/LocalizeStrings.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoHelper.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "music/MusicInfoLoader.h"
+#include "music/MusicThumbLoader.h"
+#include "music/tags/MusicInfoTag.h"
+#include "playlists/PlayList.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/URIUtils.h"
+#include "utils/log.h"
+
+using namespace KODI::GUILIB;
+using namespace KODI::GUILIB::GUIINFO;
+using namespace MUSIC_INFO;
+
+bool CMusicGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ const auto& components = CServiceBroker::GetAppComponents();
+ const auto appPlayer = components.GetComponent<CApplicationPlayer>();
+ if (item && (item->IsAudio() || (item->IsInternetStream() && appPlayer->IsPlayingAudio())))
+ {
+ CLog::Log(LOGDEBUG, "CMusicGUIInfo::InitCurrentItem({})", item->GetPath());
+
+ item->LoadMusicTag();
+
+ CMusicInfoTag* tag = item->GetMusicInfoTag(); // creates item if not yet set, so no nullptr checks needed
+ tag->SetLoaded(true);
+
+ // find a thumb for this file.
+ if (item->IsInternetStream() && !item->IsMusicDb())
+ {
+ if (!g_application.m_strPlayListFile.empty())
+ {
+ CLog::Log(LOGDEBUG, "Streaming media detected... using {} to find a thumb",
+ g_application.m_strPlayListFile);
+ CFileItem streamingItem(g_application.m_strPlayListFile,false);
+
+ CMusicThumbLoader loader;
+ loader.FillThumb(streamingItem);
+ if (streamingItem.HasArt("thumb"))
+ item->SetArt("thumb", streamingItem.GetArt("thumb"));
+ }
+ }
+ else
+ {
+ CMusicThumbLoader loader;
+ loader.LoadItem(item);
+ }
+
+ CMusicInfoLoader::LoadAdditionalTagInfo(item);
+ return true;
+ }
+ return false;
+}
+
+bool CMusicGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ // For musicplayer "offset" and "position" info labels check playlist
+ if (info.GetData1() && ((info.m_info >= MUSICPLAYER_OFFSET_POSITION_FIRST &&
+ info.m_info <= MUSICPLAYER_OFFSET_POSITION_LAST) ||
+ (info.m_info >= PLAYER_OFFSET_POSITION_FIRST && info.m_info <= PLAYER_OFFSET_POSITION_LAST)))
+ return GetPlaylistInfo(value, info);
+
+ const CMusicInfoTag* tag = item->GetMusicInfoTag();
+ if (tag)
+ {
+ switch (info.m_info)
+ {
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // PLAYER_* / MUSICPLAYER_* / LISTITEM_*
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ case PLAYER_PATH:
+ case PLAYER_FILENAME:
+ case PLAYER_FILEPATH:
+ value = tag->GetURL();
+ if (value.empty())
+ value = item->GetPath();
+ value = GUIINFO::GetFileInfoLabelValueFromPath(info.m_info, value);
+ return true;
+ case PLAYER_TITLE:
+ value = tag->GetTitle();
+ return !value.empty();
+ case MUSICPLAYER_TITLE:
+ value = tag->GetTitle();
+ return !value.empty();
+ case LISTITEM_TITLE:
+ value = tag->GetTitle();
+ return true;
+ case MUSICPLAYER_PLAYCOUNT:
+ case LISTITEM_PLAYCOUNT:
+ if (tag->GetPlayCount() > 0)
+ {
+ value = std::to_string(tag->GetPlayCount());
+ return true;
+ }
+ break;
+ case MUSICPLAYER_LASTPLAYED:
+ case LISTITEM_LASTPLAYED:
+ {
+ const CDateTime& dateTime = tag->GetLastPlayed();
+ if (dateTime.IsValid())
+ {
+ value = dateTime.GetAsLocalizedDate();
+ return true;
+ }
+ break;
+ }
+ case MUSICPLAYER_TRACK_NUMBER:
+ case LISTITEM_TRACKNUMBER:
+ if (tag->Loaded() && tag->GetTrackNumber() > 0)
+ {
+ value = StringUtils::Format("{:02}", tag->GetTrackNumber());
+ return true;
+ }
+ break;
+ case MUSICPLAYER_DISC_NUMBER:
+ case LISTITEM_DISC_NUMBER:
+ if (tag->GetDiscNumber() > 0)
+ {
+ value = std::to_string(tag->GetDiscNumber());
+ return true;
+ }
+ break;
+ case MUSICPLAYER_TOTALDISCS:
+ case LISTITEM_TOTALDISCS:
+ value = std::to_string(tag->GetTotalDiscs());
+ return true;
+ case MUSICPLAYER_DISC_TITLE:
+ case LISTITEM_DISC_TITLE:
+ value = tag->GetDiscSubtitle();
+ return true;
+ case MUSICPLAYER_ARTIST:
+ case LISTITEM_ARTIST:
+ value = tag->GetArtistString();
+ return true;
+ case MUSICPLAYER_ALBUM_ARTIST:
+ case LISTITEM_ALBUM_ARTIST:
+ value = tag->GetAlbumArtistString();
+ return true;
+ case MUSICPLAYER_CONTRIBUTORS:
+ case LISTITEM_CONTRIBUTORS:
+ if (tag->HasContributors())
+ {
+ value = tag->GetContributorsText();
+ return true;
+ }
+ break;
+ case MUSICPLAYER_CONTRIBUTOR_AND_ROLE:
+ case LISTITEM_CONTRIBUTOR_AND_ROLE:
+ if (tag->HasContributors())
+ {
+ value = tag->GetContributorsAndRolesText();
+ return true;
+ }
+ break;
+ case MUSICPLAYER_ALBUM:
+ case LISTITEM_ALBUM:
+ value = tag->GetAlbum();
+ return true;
+ case MUSICPLAYER_YEAR:
+ case LISTITEM_YEAR:
+ value = tag->GetYearString();
+ return true;
+ case MUSICPLAYER_GENRE:
+ case LISTITEM_GENRE:
+ value = StringUtils::Join(tag->GetGenre(), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator);
+ return true;
+ case MUSICPLAYER_LYRICS:
+ value = tag->GetLyrics();
+ return true;
+ case MUSICPLAYER_RATING:
+ case LISTITEM_RATING:
+ {
+ float rating = tag->GetRating();
+ if (rating > 0.f)
+ {
+ value = StringUtils::FormatNumber(rating);
+ return true;
+ }
+ break;
+ }
+ case MUSICPLAYER_RATING_AND_VOTES:
+ case LISTITEM_RATING_AND_VOTES:
+ {
+ float rating = tag->GetRating();
+ if (rating > 0.f)
+ {
+ int votes = tag->GetVotes();
+ if (votes <= 0)
+ value = StringUtils::FormatNumber(rating);
+ else
+ value =
+ StringUtils::Format(g_localizeStrings.Get(20350), StringUtils::FormatNumber(rating),
+ StringUtils::FormatNumber(votes));
+ return true;
+ }
+ break;
+ }
+ case MUSICPLAYER_USER_RATING:
+ case LISTITEM_USER_RATING:
+ if (tag->GetUserrating() > 0)
+ {
+ value = std::to_string(tag->GetUserrating());
+ return true;
+ }
+ break;
+ case MUSICPLAYER_COMMENT:
+ case LISTITEM_COMMENT:
+ value = tag->GetComment();
+ return true;
+ case MUSICPLAYER_MOOD:
+ case LISTITEM_MOOD:
+ value = tag->GetMood();
+ return true;
+ case LISTITEM_DBTYPE:
+ value = tag->GetType();
+ return true;
+ case MUSICPLAYER_DBID:
+ case LISTITEM_DBID:
+ {
+ int dbId = tag->GetDatabaseId();
+ if (dbId > -1)
+ {
+ value = std::to_string(dbId);
+ return true;
+ }
+ break;
+ }
+ case PLAYER_DURATION:
+ {
+ const auto& components = CServiceBroker::GetAppComponents();
+ const auto appPlayer = components.GetComponent<CApplicationPlayer>();
+ if (!appPlayer->IsPlayingAudio())
+ break;
+ }
+ [[fallthrough]];
+ case MUSICPLAYER_DURATION:
+ case LISTITEM_DURATION:
+ {
+ int iDuration = tag->GetDuration();
+ if (iDuration > 0)
+ {
+ value = StringUtils::SecondsToTimeString(iDuration,
+ static_cast<TIME_FORMAT>(info.m_info == LISTITEM_DURATION
+ ? info.GetData4()
+ : info.GetData1()));
+ return true;
+ }
+ break;
+ }
+ case MUSICPLAYER_BPM:
+ case LISTITEM_BPM:
+ if (tag->GetBPM() > 0)
+ {
+ value = std::to_string(tag->GetBPM());
+ return true;
+ }
+ break;
+ case MUSICPLAYER_STATIONNAME:
+ // This property can be used for example by addons to enforce/override the station name.
+ value = item->GetProperty("StationName").asString();
+ if (value.empty())
+ value = tag->GetStationName();
+ return true;
+
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ case LISTITEM_PROPERTY:
+ if (StringUtils::StartsWithNoCase(info.GetData3(), "Role."))
+ {
+ // "Role.xxxx" properties are held in music tag
+ std::string property = info.GetData3();
+ property.erase(0, 5); //Remove Role.
+ value = tag->GetArtistStringForRole(property);
+ return true;
+ }
+ break;
+ case LISTITEM_VOTES:
+ value = StringUtils::FormatNumber(tag->GetVotes());
+ return true;
+ case MUSICPLAYER_ORIGINALDATE:
+ case LISTITEM_ORIGINALDATE:
+ {
+ value = tag->GetOriginalDate();
+ if (!CServiceBroker::GetSettingsComponent()
+ ->GetAdvancedSettings()
+ ->m_bMusicLibraryUseISODates)
+ value = StringUtils::ISODateToLocalizedDate(value);
+ return true;
+ }
+ case MUSICPLAYER_RELEASEDATE:
+ case LISTITEM_RELEASEDATE:
+ {
+ value = tag->GetReleaseDate();
+ if (!CServiceBroker::GetSettingsComponent()
+ ->GetAdvancedSettings()
+ ->m_bMusicLibraryUseISODates)
+ value = StringUtils::ISODateToLocalizedDate(value);
+ return true;
+ }
+ break;
+ case LISTITEM_BITRATE:
+ {
+ int BitRate = tag->GetBitRate();
+ if (BitRate > 0)
+ {
+ value = std::to_string(BitRate);
+ return true;
+ }
+ break;
+ }
+ case LISTITEM_SAMPLERATE:
+ {
+ int sampleRate = tag->GetSampleRate();
+ if (sampleRate > 0)
+ {
+ value = StringUtils::Format("{:.5}", static_cast<double>(sampleRate) / 1000.0);
+ return true;
+ }
+ break;
+ }
+ case LISTITEM_MUSICCHANNELS:
+ {
+ int channels = tag->GetNoOfChannels();
+ if (channels > 0)
+ {
+ value = std::to_string(channels);
+ return true;
+ }
+ break;
+ }
+ case LISTITEM_ALBUMSTATUS:
+ value = tag->GetAlbumReleaseStatus();
+ return true;
+ case LISTITEM_FILENAME:
+ case LISTITEM_FILE_EXTENSION:
+ if (item->IsMusicDb())
+ value = URIUtils::GetFileName(tag->GetURL());
+ else if (item->HasVideoInfoTag()) // special handling for music videos, which have both a videotag and a musictag
+ break;
+ else
+ value = URIUtils::GetFileName(item->GetPath());
+
+ if (info.m_info == LISTITEM_FILE_EXTENSION)
+ {
+ std::string strExtension = URIUtils::GetExtension(value);
+ value = StringUtils::TrimLeft(strExtension, ".");
+ }
+ return true;
+ case LISTITEM_FOLDERNAME:
+ case LISTITEM_PATH:
+ if (item->IsMusicDb())
+ value = URIUtils::GetDirectory(tag->GetURL());
+ else if (item->HasVideoInfoTag()) // special handling for music videos, which have both a videotag and a musictag
+ break;
+ else
+ URIUtils::GetParentPath(item->GetPath(), value);
+
+ value = CURL(value).GetWithoutUserDetails();
+
+ if (info.m_info == LISTITEM_FOLDERNAME)
+ {
+ URIUtils::RemoveSlashAtEnd(value);
+ value = URIUtils::GetFileName(value);
+ }
+ return true;
+ case LISTITEM_FILENAME_AND_PATH:
+ if (item->IsMusicDb())
+ value = tag->GetURL();
+ else if (item->HasVideoInfoTag()) // special handling for music videos, which have both a videotag and a musictag
+ break;
+ else
+ value = item->GetPath();
+
+ value = CURL(value).GetWithoutUserDetails();
+ return true;
+ case LISTITEM_DATE_ADDED:
+ if (tag->GetDateAdded().IsValid())
+ {
+ value = tag->GetDateAdded().GetAsLocalizedDate();
+ return true;
+ }
+ break;
+ }
+ }
+
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // MUSICPLAYER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case MUSICPLAYER_PROPERTY:
+ if (StringUtils::StartsWithNoCase(info.GetData3(), "Role.") && item->HasMusicInfoTag())
+ {
+ // "Role.xxxx" properties are held in music tag
+ std::string property = info.GetData3();
+ property.erase(0, 5); //Remove Role.
+ value = item->GetMusicInfoTag()->GetArtistStringForRole(property);
+ return true;
+ }
+ value = item->GetProperty(info.GetData3()).asString();
+ return true;
+ case MUSICPLAYER_PLAYLISTLEN:
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST::TYPE_MUSIC)
+ {
+ value = GUIINFO::GetPlaylistLabel(PLAYLIST_LENGTH);
+ return true;
+ }
+ break;
+ case MUSICPLAYER_PLAYLISTPOS:
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST::TYPE_MUSIC)
+ {
+ value = GUIINFO::GetPlaylistLabel(PLAYLIST_POSITION);
+ return true;
+ }
+ break;
+ case MUSICPLAYER_COVER:
+ {
+ const auto& components = CServiceBroker::GetAppComponents();
+ const auto appPlayer = components.GetComponent<CApplicationPlayer>();
+ if (appPlayer->IsPlayingAudio())
+ {
+ if (fallback)
+ *fallback = "DefaultAlbumCover.png";
+ value = item->HasArt("thumb") ? item->GetArt("thumb") : "DefaultAlbumCover.png";
+ return true;
+ }
+ break;
+ }
+ case MUSICPLAYER_BITRATE:
+ {
+ int iBitrate = m_audioInfo.bitrate;
+ if (iBitrate > 0)
+ {
+ value = std::to_string(std::lrint(static_cast<double>(iBitrate) / 1000.0));
+ return true;
+ }
+ break;
+ }
+ case MUSICPLAYER_CHANNELS:
+ {
+ int iChannels = m_audioInfo.channels;
+ if (iChannels > 0)
+ {
+ value = std::to_string(iChannels);
+ return true;
+ }
+ break;
+ }
+ case MUSICPLAYER_BITSPERSAMPLE:
+ {
+ int iBPS = m_audioInfo.bitspersample;
+ if (iBPS > 0)
+ {
+ value = std::to_string(iBPS);
+ return true;
+ }
+ break;
+ }
+ case MUSICPLAYER_SAMPLERATE:
+ {
+ int iSamplerate = m_audioInfo.samplerate;
+ if (iSamplerate > 0)
+ {
+ value = StringUtils::Format("{:.5}", static_cast<double>(iSamplerate) / 1000.0);
+ return true;
+ }
+ break;
+ }
+ case MUSICPLAYER_CODEC:
+ value = m_audioInfo.codecName;
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // MUSICPM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ if (GetPartyModeLabel(value, info))
+ return true;
+
+ return false;
+}
+
+bool CMusicGUIInfo::GetPartyModeLabel(std::string& value, const CGUIInfo &info) const
+{
+ int iSongs = -1;
+
+ switch (info.m_info)
+ {
+ case MUSICPM_SONGSPLAYED:
+ iSongs = g_partyModeManager.GetSongsPlayed();
+ break;
+ case MUSICPM_MATCHINGSONGS:
+ iSongs = g_partyModeManager.GetMatchingSongs();
+ break;
+ case MUSICPM_MATCHINGSONGSPICKED:
+ iSongs = g_partyModeManager.GetMatchingSongsPicked();
+ break;
+ case MUSICPM_MATCHINGSONGSLEFT:
+ iSongs = g_partyModeManager.GetMatchingSongsLeft();
+ break;
+ case MUSICPM_RELAXEDSONGSPICKED:
+ iSongs = g_partyModeManager.GetRelaxedSongs();
+ break;
+ case MUSICPM_RANDOMSONGSPICKED:
+ iSongs = g_partyModeManager.GetRandomSongs();
+ break;
+ }
+
+ if (iSongs >= 0)
+ {
+ value = std::to_string(iSongs);
+ return true;
+ }
+
+ return false;
+}
+
+bool CMusicGUIInfo::GetPlaylistInfo(std::string& value, const CGUIInfo &info) const
+{
+ const PLAYLIST::CPlayList& playlist =
+ CServiceBroker::GetPlaylistPlayer().GetPlaylist(PLAYLIST::TYPE_MUSIC);
+ if (playlist.size() < 1)
+ return false;
+
+ int index = info.GetData2();
+ if (info.GetData1() == 1)
+ { // relative index (requires current playlist is TYPE_MUSIC)
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() != PLAYLIST::TYPE_MUSIC)
+ return false;
+
+ index = CServiceBroker::GetPlaylistPlayer().GetNextSong(index);
+ }
+
+ if (index < 0 || index >= playlist.size())
+ return false;
+
+ const CFileItemPtr playlistItem = playlist[index];
+ if (playlistItem->HasMusicInfoTag() && !playlistItem->GetMusicInfoTag()->Loaded())
+ {
+ playlistItem->LoadMusicTag();
+ playlistItem->GetMusicInfoTag()->SetLoaded();
+ }
+ // try to set a thumbnail
+ if (!playlistItem->HasArt("thumb"))
+ {
+ CMusicThumbLoader loader;
+ loader.LoadItem(playlistItem.get());
+ // still no thumb? then just the set the default cover
+ if (!playlistItem->HasArt("thumb"))
+ playlistItem->SetArt("thumb", "DefaultAlbumCover.png");
+ }
+ if (info.m_info == MUSICPLAYER_PLAYLISTPOS)
+ {
+ value = std::to_string(index + 1);
+ return true;
+ }
+ else if (info.m_info == MUSICPLAYER_COVER)
+ {
+ value = playlistItem->GetArt("thumb");
+ return true;
+ }
+
+ return GetLabel(value, playlistItem.get(), 0, CGUIInfo(info.m_info), nullptr);
+}
+
+bool CMusicGUIInfo::GetFallbackLabel(std::string& value,
+ const CFileItem* item,
+ int contextWindow,
+ const CGUIInfo& info,
+ std::string* fallback)
+{
+ // No fallback for musicplayer "offset" and "position" info labels
+ if (info.GetData1() && ((info.m_info >= MUSICPLAYER_OFFSET_POSITION_FIRST &&
+ info.m_info <= MUSICPLAYER_OFFSET_POSITION_LAST) ||
+ (info.m_info >= PLAYER_OFFSET_POSITION_FIRST && info.m_info <= PLAYER_OFFSET_POSITION_LAST)))
+ return false;
+
+ const CMusicInfoTag* tag = item->GetMusicInfoTag();
+ if (tag)
+ {
+ switch (info.m_info)
+ {
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // MUSICPLAYER_*
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ case MUSICPLAYER_TITLE:
+ value = item->GetLabel();
+ if (value.empty())
+ value = CUtil::GetTitleFromPath(item->GetPath());
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+bool CMusicGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ return false;
+}
+
+bool CMusicGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ const CFileItem* item = static_cast<const CFileItem*>(gitem);
+ const CMusicInfoTag* tag = item->GetMusicInfoTag();
+
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // MUSICPLAYER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case MUSICPLAYER_CONTENT:
+ value = StringUtils::EqualsNoCase(info.GetData3(), "files");
+ return value; // if no match for this provider, other providers shall be asked.
+ case MUSICPLAYER_HASPREVIOUS:
+ // requires current playlist be TYPE_MUSIC
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST::TYPE_MUSIC)
+ {
+ value = (CServiceBroker::GetPlaylistPlayer().GetCurrentSong() > 0); // not first song
+ return true;
+ }
+ break;
+ case MUSICPLAYER_HASNEXT:
+ // requires current playlist be TYPE_MUSIC
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST::TYPE_MUSIC)
+ {
+ value = (CServiceBroker::GetPlaylistPlayer().GetCurrentSong() <
+ (CServiceBroker::GetPlaylistPlayer().GetPlaylist(PLAYLIST::TYPE_MUSIC).size() -
+ 1)); // not last song
+ return true;
+ }
+ break;
+ case MUSICPLAYER_PLAYLISTPLAYING:
+ {
+ const auto& components = CServiceBroker::GetAppComponents();
+ const auto appPlayer = components.GetComponent<CApplicationPlayer>();
+ if (appPlayer->IsPlayingAudio() &&
+ CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST::TYPE_MUSIC)
+ {
+ value = true;
+ return true;
+ }
+ break;
+ }
+ case MUSICPLAYER_EXISTS:
+ {
+ int index = info.GetData2();
+ if (info.GetData1() == 1)
+ { // relative index
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() != PLAYLIST::TYPE_MUSIC)
+ {
+ value = false;
+ return true;
+ }
+ index += CServiceBroker::GetPlaylistPlayer().GetCurrentSong();
+ }
+ value =
+ (index >= 0 &&
+ index < CServiceBroker::GetPlaylistPlayer().GetPlaylist(PLAYLIST::TYPE_MUSIC).size());
+ return true;
+ }
+ case MUSICPLAYER_ISMULTIDISC:
+ if (tag)
+ {
+ value = (item->GetMusicInfoTag()->GetTotalDiscs() > 1);
+ return true;
+ }
+ break;
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // MUSICPM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case MUSICPM_ENABLED:
+ value = g_partyModeManager.IsEnabled();
+ return true;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case LISTITEM_IS_BOXSET:
+ if (tag)
+ {
+ value = tag->GetBoxset() == true;
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/MusicGUIInfo.h b/xbmc/guilib/guiinfo/MusicGUIInfo.h
new file mode 100644
index 0000000..4132ca6
--- /dev/null
+++ b/xbmc/guilib/guiinfo/MusicGUIInfo.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CMusicGUIInfo : public CGUIInfoProvider
+{
+public:
+ CMusicGUIInfo() = default;
+ ~CMusicGUIInfo() override = default;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetFallbackLabel(std::string& value,
+ const CFileItem* item,
+ int contextWindow,
+ const CGUIInfo& info,
+ std::string* fallback) override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+
+private:
+ bool GetPartyModeLabel(std::string& value, const CGUIInfo &info) const;
+ bool GetPlaylistInfo(std::string& value, const CGUIInfo &info) const;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/PicturesGUIInfo.cpp b/xbmc/guilib/guiinfo/PicturesGUIInfo.cpp
new file mode 100644
index 0000000..6115517
--- /dev/null
+++ b/xbmc/guilib/guiinfo/PicturesGUIInfo.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/PicturesGUIInfo.h"
+
+#include "FileItem.h"
+#include "ServiceBroker.h"
+#include "URL.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "pictures/GUIWindowSlideShow.h"
+#include "pictures/PictureInfoTag.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+#include "utils/log.h"
+
+#include <map>
+
+using namespace KODI::GUILIB::GUIINFO;
+
+static const std::map<int, int> listitem2slideshow_map =
+{
+ { LISTITEM_PICTURE_RESOLUTION , SLIDESHOW_RESOLUTION },
+ { LISTITEM_PICTURE_LONGDATE , SLIDESHOW_EXIF_LONG_DATE },
+ { LISTITEM_PICTURE_LONGDATETIME , SLIDESHOW_EXIF_LONG_DATE_TIME },
+ { LISTITEM_PICTURE_DATE , SLIDESHOW_EXIF_DATE },
+ { LISTITEM_PICTURE_DATETIME , SLIDESHOW_EXIF_DATE_TIME },
+ { LISTITEM_PICTURE_COMMENT , SLIDESHOW_COMMENT },
+ { LISTITEM_PICTURE_CAPTION , SLIDESHOW_IPTC_CAPTION },
+ { LISTITEM_PICTURE_DESC , SLIDESHOW_EXIF_DESCRIPTION },
+ { LISTITEM_PICTURE_KEYWORDS , SLIDESHOW_IPTC_KEYWORDS },
+ { LISTITEM_PICTURE_CAM_MAKE , SLIDESHOW_EXIF_CAMERA_MAKE },
+ { LISTITEM_PICTURE_CAM_MODEL , SLIDESHOW_EXIF_CAMERA_MODEL },
+ { LISTITEM_PICTURE_APERTURE , SLIDESHOW_EXIF_APERTURE },
+ { LISTITEM_PICTURE_FOCAL_LEN , SLIDESHOW_EXIF_FOCAL_LENGTH },
+ { LISTITEM_PICTURE_FOCUS_DIST , SLIDESHOW_EXIF_FOCUS_DIST },
+ { LISTITEM_PICTURE_EXP_MODE , SLIDESHOW_EXIF_EXPOSURE_MODE },
+ { LISTITEM_PICTURE_EXP_TIME , SLIDESHOW_EXIF_EXPOSURE_TIME },
+ { LISTITEM_PICTURE_ISO , SLIDESHOW_EXIF_ISO_EQUIV },
+ { LISTITEM_PICTURE_AUTHOR , SLIDESHOW_IPTC_AUTHOR },
+ { LISTITEM_PICTURE_BYLINE , SLIDESHOW_IPTC_BYLINE },
+ { LISTITEM_PICTURE_BYLINE_TITLE , SLIDESHOW_IPTC_BYLINE_TITLE },
+ { LISTITEM_PICTURE_CATEGORY , SLIDESHOW_IPTC_CATEGORY },
+ { LISTITEM_PICTURE_CCD_WIDTH , SLIDESHOW_EXIF_CCD_WIDTH },
+ { LISTITEM_PICTURE_CITY , SLIDESHOW_IPTC_CITY },
+ { LISTITEM_PICTURE_URGENCY , SLIDESHOW_IPTC_URGENCY },
+ { LISTITEM_PICTURE_COPYRIGHT_NOTICE , SLIDESHOW_IPTC_COPYRIGHT_NOTICE },
+ { LISTITEM_PICTURE_COUNTRY , SLIDESHOW_IPTC_COUNTRY },
+ { LISTITEM_PICTURE_COUNTRY_CODE , SLIDESHOW_IPTC_COUNTRY_CODE },
+ { LISTITEM_PICTURE_CREDIT , SLIDESHOW_IPTC_CREDIT },
+ { LISTITEM_PICTURE_IPTCDATE , SLIDESHOW_IPTC_DATE },
+ { LISTITEM_PICTURE_DIGITAL_ZOOM , SLIDESHOW_EXIF_DIGITAL_ZOOM, },
+ { LISTITEM_PICTURE_EXPOSURE , SLIDESHOW_EXIF_EXPOSURE },
+ { LISTITEM_PICTURE_EXPOSURE_BIAS , SLIDESHOW_EXIF_EXPOSURE_BIAS },
+ { LISTITEM_PICTURE_FLASH_USED , SLIDESHOW_EXIF_FLASH_USED },
+ { LISTITEM_PICTURE_HEADLINE , SLIDESHOW_IPTC_HEADLINE },
+ { LISTITEM_PICTURE_COLOUR , SLIDESHOW_COLOUR },
+ { LISTITEM_PICTURE_LIGHT_SOURCE , SLIDESHOW_EXIF_LIGHT_SOURCE },
+ { LISTITEM_PICTURE_METERING_MODE , SLIDESHOW_EXIF_METERING_MODE },
+ { LISTITEM_PICTURE_OBJECT_NAME , SLIDESHOW_IPTC_OBJECT_NAME },
+ { LISTITEM_PICTURE_ORIENTATION , SLIDESHOW_EXIF_ORIENTATION },
+ { LISTITEM_PICTURE_PROCESS , SLIDESHOW_PROCESS },
+ { LISTITEM_PICTURE_REF_SERVICE , SLIDESHOW_IPTC_REF_SERVICE },
+ { LISTITEM_PICTURE_SOURCE , SLIDESHOW_IPTC_SOURCE },
+ { LISTITEM_PICTURE_SPEC_INSTR , SLIDESHOW_IPTC_SPEC_INSTR },
+ { LISTITEM_PICTURE_STATE , SLIDESHOW_IPTC_STATE },
+ { LISTITEM_PICTURE_SUP_CATEGORIES , SLIDESHOW_IPTC_SUP_CATEGORIES },
+ { LISTITEM_PICTURE_TX_REFERENCE , SLIDESHOW_IPTC_TX_REFERENCE },
+ { LISTITEM_PICTURE_WHITE_BALANCE , SLIDESHOW_EXIF_WHITE_BALANCE },
+ { LISTITEM_PICTURE_IMAGETYPE , SLIDESHOW_IPTC_IMAGETYPE },
+ { LISTITEM_PICTURE_SUBLOCATION , SLIDESHOW_IPTC_SUBLOCATION },
+ { LISTITEM_PICTURE_TIMECREATED , SLIDESHOW_IPTC_TIMECREATED },
+ { LISTITEM_PICTURE_GPS_LAT , SLIDESHOW_EXIF_GPS_LATITUDE },
+ { LISTITEM_PICTURE_GPS_LON , SLIDESHOW_EXIF_GPS_LONGITUDE },
+ { LISTITEM_PICTURE_GPS_ALT , SLIDESHOW_EXIF_GPS_ALTITUDE }
+};
+
+CPicturesGUIInfo::CPicturesGUIInfo() = default;
+
+CPicturesGUIInfo::~CPicturesGUIInfo() = default;
+
+void CPicturesGUIInfo::SetCurrentSlide(CFileItem *item)
+{
+ if (m_currentSlide && item && m_currentSlide->GetPath() == item->GetPath())
+ return;
+
+ if (item)
+ {
+ if (item->HasPictureInfoTag()) // Note: item may also be a video
+ {
+ CPictureInfoTag* tag = item->GetPictureInfoTag();
+ if (!tag->Loaded()) // If picture metadata has not been loaded yet, load it now
+ tag->Load(item->GetPath());
+ }
+ m_currentSlide.reset(new CFileItem(*item));
+ }
+ else if (m_currentSlide)
+ {
+ m_currentSlide.reset();
+ }
+}
+
+const CFileItem* CPicturesGUIInfo::GetCurrentSlide() const
+{
+ return m_currentSlide.get();
+}
+
+bool CPicturesGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ return false;
+}
+
+bool CPicturesGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ if (item->IsPicture() && info.m_info >= LISTITEM_PICTURE_START && info.m_info <= LISTITEM_PICTURE_END)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ const auto& it = listitem2slideshow_map.find(info.m_info);
+ if (it != listitem2slideshow_map.end())
+ {
+ if (item->HasPictureInfoTag())
+ {
+ value = item->GetPictureInfoTag()->GetInfo(it->second);
+ return true;
+ }
+ }
+ else
+ {
+ CLog::Log(LOGERROR,
+ "CPicturesGUIInfo::GetLabel - cannot map LISTITEM ({}) to SLIDESHOW label!",
+ info.m_info);
+ return false;
+ }
+ }
+ else if (m_currentSlide && info.m_info >= SLIDESHOW_LABELS_START && info.m_info <= SLIDESHOW_LABELS_END)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SLIDESHOW_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ switch (info.m_info)
+ {
+ case SLIDESHOW_FILE_NAME:
+ {
+ value = URIUtils::GetFileName(m_currentSlide->GetPath());
+ return true;
+ }
+ case SLIDESHOW_FILE_PATH:
+ {
+ const std::string path = URIUtils::GetDirectory(m_currentSlide->GetPath());
+ value = CURL(path).GetWithoutUserDetails();
+ return true;
+ }
+ case SLIDESHOW_FILE_SIZE:
+ {
+ if (!m_currentSlide->m_bIsFolder || m_currentSlide->m_dwSize)
+ {
+ value = StringUtils::SizeToString(m_currentSlide->m_dwSize);
+ return true;
+ }
+ break;
+ }
+ case SLIDESHOW_FILE_DATE:
+ {
+ if (m_currentSlide->m_dateTime.IsValid())
+ {
+ value = m_currentSlide->m_dateTime.GetAsLocalizedDate();
+ return true;
+ }
+ break;
+ }
+ case SLIDESHOW_INDEX:
+ {
+ CGUIWindowSlideShow *slideshow = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIWindowSlideShow>(WINDOW_SLIDESHOW);
+ if (slideshow && slideshow->NumSlides())
+ {
+ value = StringUtils::Format("{}/{}", slideshow->CurrentSlide(), slideshow->NumSlides());
+ return true;
+ }
+ break;
+ }
+ default:
+ {
+ value = m_currentSlide->GetPictureInfoTag()->GetInfo(info.m_info);
+ return true;
+ }
+ }
+ }
+
+ if (item->IsPicture())
+ {
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ switch (info.m_info)
+ {
+ case LISTITEM_PICTURE_PATH:
+ {
+ if (!(item->IsZIP() || item->IsRAR() || item->IsCBZ() || item->IsCBR()))
+ {
+ value = item->GetPath();
+ return true;
+ }
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool CPicturesGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ return false;
+}
+
+bool CPicturesGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SLIDESHOW_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SLIDESHOW_ISPAUSED:
+ {
+ CGUIWindowSlideShow *slideShow = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIWindowSlideShow>(WINDOW_SLIDESHOW);
+ value = (slideShow && slideShow->IsPaused());
+ return true;
+ }
+ case SLIDESHOW_ISRANDOM:
+ {
+ CGUIWindowSlideShow *slideShow = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIWindowSlideShow>(WINDOW_SLIDESHOW);
+ value = (slideShow && slideShow->IsShuffled());
+ return true;
+ }
+ case SLIDESHOW_ISACTIVE:
+ {
+ CGUIWindowSlideShow *slideShow = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIWindowSlideShow>(WINDOW_SLIDESHOW);
+ value = (slideShow && slideShow->InSlideShow());
+ return true;
+ }
+ case SLIDESHOW_ISVIDEO:
+ {
+ CGUIWindowSlideShow *slideShow = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIWindowSlideShow>(WINDOW_SLIDESHOW);
+ value = (slideShow && slideShow->GetCurrentSlide() && slideShow->GetCurrentSlide()->IsVideo());
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/PicturesGUIInfo.h b/xbmc/guilib/guiinfo/PicturesGUIInfo.h
new file mode 100644
index 0000000..68cdb4c
--- /dev/null
+++ b/xbmc/guilib/guiinfo/PicturesGUIInfo.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+
+#include <memory>
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CPicturesGUIInfo : public CGUIInfoProvider
+{
+public:
+ CPicturesGUIInfo();
+ ~CPicturesGUIInfo() override;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+
+ void SetCurrentSlide(CFileItem *item);
+ const CFileItem* GetCurrentSlide() const;
+
+private:
+ std::unique_ptr<CFileItem> m_currentSlide;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/PlayerGUIInfo.cpp b/xbmc/guilib/guiinfo/PlayerGUIInfo.cpp
new file mode 100644
index 0000000..dfb9455
--- /dev/null
+++ b/xbmc/guilib/guiinfo/PlayerGUIInfo.cpp
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/PlayerGUIInfo.h"
+
+#include "FileItem.h"
+#include "PlayListPlayer.h"
+#include "ServiceBroker.h"
+#include "URL.h"
+#include "Util.h"
+#include "application/Application.h"
+#include "application/ApplicationComponents.h"
+#include "application/ApplicationPlayer.h"
+#include "application/ApplicationVolumeHandling.h"
+#include "cores/AudioEngine/Utils/AEUtil.h"
+#include "cores/DataCacheCore.h"
+#include "cores/EdlEdit.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIDialog.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoHelper.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
+
+#include <charconv>
+#include <cmath>
+
+using namespace KODI::GUILIB::GUIINFO;
+
+CPlayerGUIInfo::CPlayerGUIInfo()
+ : m_appPlayer(CServiceBroker::GetAppComponents().GetComponent<CApplicationPlayer>()),
+ m_appVolume(CServiceBroker::GetAppComponents().GetComponent<CApplicationVolumeHandling>())
+{
+}
+
+CPlayerGUIInfo::~CPlayerGUIInfo() = default;
+
+int CPlayerGUIInfo::GetTotalPlayTime() const
+{
+ return std::lrint(g_application.GetTotalTime());
+}
+
+int CPlayerGUIInfo::GetPlayTime() const
+{
+ return std::lrint(g_application.GetTime());
+}
+
+int CPlayerGUIInfo::GetPlayTimeRemaining() const
+{
+ int iReverse = GetTotalPlayTime() - std::lrint(g_application.GetTime());
+ return iReverse > 0 ? iReverse : 0;
+}
+
+float CPlayerGUIInfo::GetSeekPercent() const
+{
+ int iTotal = GetTotalPlayTime();
+ if (iTotal == 0)
+ return 0.0f;
+
+ float fPercentPlayTime = static_cast<float>(GetPlayTime() * 1000) / iTotal * 0.1f;
+ float fPercentPerSecond = 100.0f / static_cast<float>(iTotal);
+ float fPercent =
+ fPercentPlayTime + fPercentPerSecond * m_appPlayer->GetSeekHandler().GetSeekSize();
+ fPercent = std::max(0.0f, std::min(fPercent, 100.0f));
+ return fPercent;
+}
+
+std::string CPlayerGUIInfo::GetCurrentPlayTime(TIME_FORMAT format) const
+{
+ if (format == TIME_FORMAT_GUESS && GetTotalPlayTime() >= 3600)
+ format = TIME_FORMAT_HH_MM_SS;
+
+ return StringUtils::SecondsToTimeString(std::lrint(GetPlayTime()), format);
+}
+
+std::string CPlayerGUIInfo::GetCurrentPlayTimeRemaining(TIME_FORMAT format) const
+{
+ if (format == TIME_FORMAT_GUESS && GetTotalPlayTime() >= 3600)
+ format = TIME_FORMAT_HH_MM_SS;
+
+ int iTimeRemaining = GetPlayTimeRemaining();
+ if (iTimeRemaining)
+ return StringUtils::SecondsToTimeString(iTimeRemaining, format);
+
+ return std::string();
+}
+
+std::string CPlayerGUIInfo::GetDuration(TIME_FORMAT format) const
+{
+ int iTotal = GetTotalPlayTime();
+ if (iTotal > 0)
+ {
+ if (format == TIME_FORMAT_GUESS && iTotal >= 3600)
+ format = TIME_FORMAT_HH_MM_SS;
+ return StringUtils::SecondsToTimeString(iTotal, format);
+ }
+ return std::string();
+}
+
+std::string CPlayerGUIInfo::GetCurrentSeekTime(TIME_FORMAT format) const
+{
+ if (format == TIME_FORMAT_GUESS && GetTotalPlayTime() >= 3600)
+ format = TIME_FORMAT_HH_MM_SS;
+
+ return StringUtils::SecondsToTimeString(
+ g_application.GetTime() + m_appPlayer->GetSeekHandler().GetSeekSize(), format);
+}
+
+std::string CPlayerGUIInfo::GetSeekTime(TIME_FORMAT format) const
+{
+ if (!m_appPlayer->GetSeekHandler().HasTimeCode())
+ return std::string();
+
+ int iSeekTimeCode = m_appPlayer->GetSeekHandler().GetTimeCodeSeconds();
+ if (format == TIME_FORMAT_GUESS && iSeekTimeCode >= 3600)
+ format = TIME_FORMAT_HH_MM_SS;
+
+ return StringUtils::SecondsToTimeString(iSeekTimeCode, format);
+}
+
+void CPlayerGUIInfo::SetShowInfo(bool showinfo)
+{
+ if (showinfo != m_playerShowInfo)
+ {
+ m_playerShowInfo = showinfo;
+ m_events.Publish(PlayerShowInfoChangedEvent(m_playerShowInfo));
+ }
+}
+
+bool CPlayerGUIInfo::ToggleShowInfo()
+{
+ SetShowInfo(!m_playerShowInfo);
+ return m_playerShowInfo;
+}
+
+bool CPlayerGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ if (item && m_appPlayer->IsPlaying())
+ {
+ CLog::Log(LOGDEBUG, "CPlayerGUIInfo::InitCurrentItem({})", CURL::GetRedacted(item->GetPath()));
+ m_currentItem.reset(new CFileItem(*item));
+ }
+ else
+ {
+ m_currentItem.reset();
+ }
+ return false;
+}
+
+bool CPlayerGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // PLAYER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case PLAYER_SEEKOFFSET:
+ {
+ int lastSeekOffset = CServiceBroker::GetDataCacheCore().GetSeekOffSet();
+ std::string seekOffset = StringUtils::SecondsToTimeString(
+ std::abs(lastSeekOffset / 1000), static_cast<TIME_FORMAT>(info.GetData1()));
+ if (lastSeekOffset < 0)
+ value = "-" + seekOffset;
+ else if (lastSeekOffset > 0)
+ value = "+" + seekOffset;
+ return true;
+ }
+ case PLAYER_PROGRESS:
+ value = std::to_string(std::lrintf(g_application.GetPercentage()));
+ return true;
+ case PLAYER_PROGRESS_CACHE:
+ value = std::to_string(std::lrintf(g_application.GetCachePercentage()));
+ return true;
+ case PLAYER_VOLUME:
+ value =
+ StringUtils::Format("{:2.1f} dB", CAEUtil::PercentToGain(m_appVolume->GetVolumeRatio()));
+ return true;
+ case PLAYER_SUBTITLE_DELAY:
+ value = StringUtils::Format("{:2.3f} s", m_appPlayer->GetVideoSettings().m_SubtitleDelay);
+ return true;
+ case PLAYER_AUDIO_DELAY:
+ value = StringUtils::Format("{:2.3f} s", m_appPlayer->GetVideoSettings().m_AudioDelay);
+ return true;
+ case PLAYER_CHAPTER:
+ value = StringUtils::Format("{:02}", m_appPlayer->GetChapter());
+ return true;
+ case PLAYER_CHAPTERCOUNT:
+ value = StringUtils::Format("{:02}", m_appPlayer->GetChapterCount());
+ return true;
+ case PLAYER_CHAPTERNAME:
+ m_appPlayer->GetChapterName(value);
+ return true;
+ case PLAYER_PATH:
+ case PLAYER_FILENAME:
+ case PLAYER_FILEPATH:
+ value = GUIINFO::GetFileInfoLabelValueFromPath(info.m_info, item->GetPath());
+ return true;
+ case PLAYER_TITLE:
+ // use label or drop down to title from path
+ value = item->GetLabel();
+ if (value.empty())
+ value = CUtil::GetTitleFromPath(item->GetPath());
+ return true;
+ case PLAYER_PLAYSPEED:
+ {
+ float speed = m_appPlayer->GetPlaySpeed();
+ if (speed == 1.0f)
+ speed = m_appPlayer->GetPlayTempo();
+ value = StringUtils::Format("{:.2f}", speed);
+ return true;
+ }
+ case PLAYER_TIME:
+ value = GetCurrentPlayTime(static_cast<TIME_FORMAT>(info.GetData1()));
+ return true;
+ case PLAYER_START_TIME:
+ {
+ const CDateTime time(m_appPlayer->GetStartTime());
+ value = time.GetAsLocalizedTime(static_cast<TIME_FORMAT>(info.GetData1()));
+ return true;
+ }
+ case PLAYER_DURATION:
+ value = GetDuration(static_cast<TIME_FORMAT>(info.GetData1()));
+ return true;
+ case PLAYER_TIME_REMAINING:
+ value = GetCurrentPlayTimeRemaining(static_cast<TIME_FORMAT>(info.GetData1()));
+ return true;
+ case PLAYER_FINISH_TIME:
+ {
+ CDateTime time(CDateTime::GetCurrentDateTime());
+ int playTimeRemaining = GetPlayTimeRemaining();
+ float speed = m_appPlayer->GetPlaySpeed();
+ float tempo = m_appPlayer->GetPlayTempo();
+ if (speed == 1.0f)
+ playTimeRemaining /= tempo;
+ time += CDateTimeSpan(0, 0, 0, playTimeRemaining);
+ value = time.GetAsLocalizedTime(static_cast<TIME_FORMAT>(info.GetData1()));
+ return true;
+ }
+ case PLAYER_TIME_SPEED:
+ {
+ float speed = m_appPlayer->GetPlaySpeed();
+ if (speed != 1.0f)
+ value = StringUtils::Format("{} ({}x)",
+ GetCurrentPlayTime(static_cast<TIME_FORMAT>(info.GetData1())),
+ static_cast<int>(speed));
+ else
+ value = GetCurrentPlayTime(TIME_FORMAT_GUESS);
+ return true;
+ }
+ case PLAYER_SEEKTIME:
+ value = GetCurrentSeekTime(static_cast<TIME_FORMAT>(info.GetData1()));
+ return true;
+ case PLAYER_SEEKSTEPSIZE:
+ {
+ int seekSize = m_appPlayer->GetSeekHandler().GetSeekSize();
+ std::string strSeekSize = StringUtils::SecondsToTimeString(abs(seekSize), static_cast<TIME_FORMAT>(info.GetData1()));
+ if (seekSize < 0)
+ value = "-" + strSeekSize;
+ if (seekSize > 0)
+ value = "+" + strSeekSize;
+ return true;
+ }
+ case PLAYER_SEEKNUMERIC:
+ value = GetSeekTime(static_cast<TIME_FORMAT>(info.GetData1()));
+ return !value.empty();
+ case PLAYER_CACHELEVEL:
+ {
+ int iLevel = m_appPlayer->GetCacheLevel();
+ if (iLevel >= 0)
+ {
+ value = std::to_string(iLevel);
+ return true;
+ }
+ break;
+ }
+ case PLAYER_ITEM_ART:
+ value = item->GetArt(info.GetData3());
+ return true;
+ case PLAYER_ICON:
+ value = item->GetArt("thumb");
+ if (value.empty())
+ value = item->GetArt("icon");
+ if (fallback)
+ *fallback = item->GetArt("icon");
+ return true;
+ case PLAYER_EDITLIST:
+ case PLAYER_CUTS:
+ case PLAYER_SCENE_MARKERS:
+ case PLAYER_CUTLIST:
+ case PLAYER_CHAPTERS:
+ value = GetContentRanges(info.m_info);
+ return true;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // PLAYER_PROCESS_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case PLAYER_PROCESS_VIDEODECODER:
+ value = CServiceBroker::GetDataCacheCore().GetVideoDecoderName();
+ return true;
+ case PLAYER_PROCESS_DEINTMETHOD:
+ value = CServiceBroker::GetDataCacheCore().GetVideoDeintMethod();
+ return true;
+ case PLAYER_PROCESS_PIXELFORMAT:
+ value = CServiceBroker::GetDataCacheCore().GetVideoPixelFormat();
+ return true;
+ case PLAYER_PROCESS_VIDEOFPS:
+ value = StringUtils::Format("{:.3f}", CServiceBroker::GetDataCacheCore().GetVideoFps());
+ return true;
+ case PLAYER_PROCESS_VIDEODAR:
+ value = StringUtils::Format("{:.2f}", CServiceBroker::GetDataCacheCore().GetVideoDAR());
+ return true;
+ case PLAYER_PROCESS_VIDEOWIDTH:
+ value = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetVideoWidth());
+ return true;
+ case PLAYER_PROCESS_VIDEOHEIGHT:
+ value = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetVideoHeight());
+ return true;
+ case PLAYER_PROCESS_VIDEOSCANTYPE:
+ value = CServiceBroker::GetDataCacheCore().IsVideoInterlaced() ? "i" : "p";
+ return true;
+ case PLAYER_PROCESS_AUDIODECODER:
+ value = CServiceBroker::GetDataCacheCore().GetAudioDecoderName();
+ return true;
+ case PLAYER_PROCESS_AUDIOCHANNELS:
+ value = CServiceBroker::GetDataCacheCore().GetAudioChannels();
+ return true;
+ case PLAYER_PROCESS_AUDIOSAMPLERATE:
+ value = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetAudioSampleRate());
+ return true;
+ case PLAYER_PROCESS_AUDIOBITSPERSAMPLE:
+ value = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetAudioBitsPerSample());
+ return true;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // PLAYLIST_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case PLAYLIST_LENGTH:
+ case PLAYLIST_POSITION:
+ case PLAYLIST_RANDOM:
+ case PLAYLIST_REPEAT:
+ value = GUIINFO::GetPlaylistLabel(info.m_info, info.GetData1());
+ return true;
+ }
+
+ return false;
+}
+
+bool CPlayerGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // PLAYER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case PLAYER_VOLUME:
+ value = static_cast<int>(m_appVolume->GetVolumePercent());
+ return true;
+ case PLAYER_PROGRESS:
+ value = std::lrintf(g_application.GetPercentage());
+ return true;
+ case PLAYER_PROGRESS_CACHE:
+ value = std::lrintf(g_application.GetCachePercentage());
+ return true;
+ case PLAYER_SEEKBAR:
+ value = std::lrintf(GetSeekPercent());
+ return true;
+ case PLAYER_CACHELEVEL:
+ value = m_appPlayer->GetCacheLevel();
+ return true;
+ case PLAYER_CHAPTER:
+ value = m_appPlayer->GetChapter();
+ return true;
+ case PLAYER_CHAPTERCOUNT:
+ value = m_appPlayer->GetChapterCount();
+ return true;
+ case PLAYER_SUBTITLE_DELAY:
+ value = m_appPlayer->GetSubtitleDelay();
+ return true;
+ case PLAYER_AUDIO_DELAY:
+ value = m_appPlayer->GetAudioDelay();
+ return true;
+ }
+
+ return false;
+}
+
+bool CPlayerGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ const CFileItem *item = nullptr;
+ if (gitem->IsFileItem())
+ item = static_cast<const CFileItem*>(gitem);
+
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // PLAYER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case PLAYER_SHOWINFO:
+ value = m_playerShowInfo;
+ return true;
+ case PLAYER_SHOWTIME:
+ value = m_playerShowTime;
+ return true;
+ case PLAYER_MUTED:
+ value = (m_appVolume->IsMuted() ||
+ m_appVolume->GetVolumeRatio() <= CApplicationVolumeHandling::VOLUME_MINIMUM);
+ return true;
+ case PLAYER_HAS_MEDIA:
+ value = m_appPlayer->IsPlaying();
+ return true;
+ case PLAYER_HAS_AUDIO:
+ value = m_appPlayer->IsPlayingAudio();
+ return true;
+ case PLAYER_HAS_VIDEO:
+ value = m_appPlayer->IsPlayingVideo();
+ return true;
+ case PLAYER_HAS_GAME:
+ value = m_appPlayer->IsPlayingGame();
+ return true;
+ case PLAYER_PLAYING:
+ value = m_appPlayer->GetPlaySpeed() == 1.0f;
+ return true;
+ case PLAYER_PAUSED:
+ value = m_appPlayer->IsPausedPlayback();
+ return true;
+ case PLAYER_REWINDING:
+ value = m_appPlayer->GetPlaySpeed() < 0.0f;
+ return true;
+ case PLAYER_FORWARDING:
+ value = m_appPlayer->GetPlaySpeed() > 1.5f;
+ return true;
+ case PLAYER_REWINDING_2x:
+ value = m_appPlayer->GetPlaySpeed() == -2;
+ return true;
+ case PLAYER_REWINDING_4x:
+ value = m_appPlayer->GetPlaySpeed() == -4;
+ return true;
+ case PLAYER_REWINDING_8x:
+ value = m_appPlayer->GetPlaySpeed() == -8;
+ return true;
+ case PLAYER_REWINDING_16x:
+ value = m_appPlayer->GetPlaySpeed() == -16;
+ return true;
+ case PLAYER_REWINDING_32x:
+ value = m_appPlayer->GetPlaySpeed() == -32;
+ return true;
+ case PLAYER_FORWARDING_2x:
+ value = m_appPlayer->GetPlaySpeed() == 2;
+ return true;
+ case PLAYER_FORWARDING_4x:
+ value = m_appPlayer->GetPlaySpeed() == 4;
+ return true;
+ case PLAYER_FORWARDING_8x:
+ value = m_appPlayer->GetPlaySpeed() == 8;
+ return true;
+ case PLAYER_FORWARDING_16x:
+ value = m_appPlayer->GetPlaySpeed() == 16;
+ return true;
+ case PLAYER_FORWARDING_32x:
+ value = m_appPlayer->GetPlaySpeed() == 32;
+ return true;
+ case PLAYER_CAN_PAUSE:
+ value = m_appPlayer->CanPause();
+ return true;
+ case PLAYER_CAN_SEEK:
+ value = m_appPlayer->CanSeek();
+ return true;
+ case PLAYER_SUPPORTS_TEMPO:
+ value = m_appPlayer->SupportsTempo();
+ return true;
+ case PLAYER_IS_TEMPO:
+ value = (m_appPlayer->GetPlayTempo() != 1.0f && m_appPlayer->GetPlaySpeed() == 1.0f);
+ return true;
+ case PLAYER_CACHING:
+ value = m_appPlayer->IsCaching();
+ return true;
+ case PLAYER_SEEKBAR:
+ {
+ CGUIDialog *seekBar = CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_SEEK_BAR);
+ value = seekBar ? seekBar->IsDialogRunning() : false;
+ return true;
+ }
+ case PLAYER_SEEKING:
+ value = m_appPlayer->GetSeekHandler().InProgress();
+ return true;
+ case PLAYER_HASPERFORMEDSEEK:
+ {
+ int requestedLastSecondInterval{0};
+ std::from_chars_result result =
+ std::from_chars(info.GetData3().data(), info.GetData3().data() + info.GetData3().size(),
+ requestedLastSecondInterval);
+ if (result.ec == std::errc::invalid_argument)
+ {
+ value = false;
+ return false;
+ }
+
+ value = CServiceBroker::GetDataCacheCore().HasPerformedSeek(requestedLastSecondInterval);
+ return true;
+ }
+ case PLAYER_PASSTHROUGH:
+ value = m_appPlayer->IsPassthrough();
+ return true;
+ case PLAYER_ISINTERNETSTREAM:
+ if (item)
+ {
+ value = URIUtils::IsInternetStream(item->GetDynPath());
+ return true;
+ }
+ break;
+ case PLAYER_HAS_PROGRAMS:
+ value = (m_appPlayer->GetProgramsCount() > 1) ? true : false;
+ return true;
+ case PLAYER_HAS_RESOLUTIONS:
+ value = CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenRoot() &&
+ CResolutionUtils::HasWhitelist();
+ return true;
+ case PLAYER_HASDURATION:
+ value = g_application.GetTotalTime() > 0;
+ return true;
+ case PLAYER_FRAMEADVANCE:
+ value = CServiceBroker::GetDataCacheCore().IsFrameAdvance();
+ return true;
+ case PLAYER_HAS_SCENE_MARKERS:
+ value = !CServiceBroker::GetDataCacheCore().GetSceneMarkers().empty();
+ return true;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // PLAYLIST_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case PLAYLIST_ISRANDOM:
+ {
+ PLAYLIST::CPlayListPlayer& player = CServiceBroker::GetPlaylistPlayer();
+ PLAYLIST::Id playlistid = info.GetData1();
+ if (info.GetData2() > 0 && playlistid != PLAYLIST::TYPE_NONE)
+ value = player.IsShuffled(playlistid);
+ else
+ value = player.IsShuffled(player.GetCurrentPlaylist());
+ return true;
+ }
+ case PLAYLIST_ISREPEAT:
+ {
+ PLAYLIST::CPlayListPlayer& player = CServiceBroker::GetPlaylistPlayer();
+ PLAYLIST::Id playlistid = info.GetData1();
+ if (info.GetData2() > 0 && playlistid != PLAYLIST::TYPE_NONE)
+ value = (player.GetRepeat(playlistid) == PLAYLIST::RepeatState::ALL);
+ else
+ value = player.GetRepeat(player.GetCurrentPlaylist()) == PLAYLIST::RepeatState::ALL;
+ return true;
+ }
+ case PLAYLIST_ISREPEATONE:
+ {
+ PLAYLIST::CPlayListPlayer& player = CServiceBroker::GetPlaylistPlayer();
+ PLAYLIST::Id playlistid = info.GetData1();
+ if (info.GetData2() > 0 && playlistid != PLAYLIST::TYPE_NONE)
+ value = (player.GetRepeat(playlistid) == PLAYLIST::RepeatState::ONE);
+ else
+ value = player.GetRepeat(player.GetCurrentPlaylist()) == PLAYLIST::RepeatState::ONE;
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // PLAYER_PROCESS_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case PLAYER_PROCESS_VIDEOHWDECODER:
+ value = CServiceBroker::GetDataCacheCore().IsVideoHwDecoder();
+ return true;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case LISTITEM_ISPLAYING:
+ {
+ if (item)
+ {
+ if (item->HasProperty("playlistposition"))
+ {
+ value = static_cast<int>(item->GetProperty("playlisttype").asInteger()) == CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() &&
+ static_cast<int>(item->GetProperty("playlistposition").asInteger()) == CServiceBroker::GetPlaylistPlayer().GetCurrentSong();
+ return true;
+ }
+ else if (m_currentItem && !m_currentItem->GetPath().empty())
+ {
+ if (!g_application.m_strPlayListFile.empty())
+ {
+ //playlist file that is currently playing or the playlistitem that is currently playing.
+ value = item->IsPath(g_application.m_strPlayListFile) || m_currentItem->IsSamePath(item);
+ }
+ else
+ {
+ value = m_currentItem->IsSamePath(item);
+ }
+ return true;
+ }
+ }
+ break;
+ }
+ }
+
+ return false;
+}
+
+std::string CPlayerGUIInfo::GetContentRanges(int iInfo) const
+{
+ std::string values;
+
+ CDataCacheCore& data = CServiceBroker::GetDataCacheCore();
+ std::vector<std::pair<float, float>> ranges;
+
+ std::time_t start;
+ int64_t current;
+ int64_t min;
+ int64_t max;
+ data.GetPlayTimes(start, current, min, max);
+
+ std::time_t duration = max - start * 1000;
+ if (duration > 0)
+ {
+ switch (iInfo)
+ {
+ case PLAYER_EDITLIST:
+ case PLAYER_CUTLIST:
+ ranges = GetEditList(data, duration);
+ break;
+ case PLAYER_CUTS:
+ ranges = GetCuts(data, duration);
+ break;
+ case PLAYER_SCENE_MARKERS:
+ ranges = GetSceneMarkers(data, duration);
+ break;
+ case PLAYER_CHAPTERS:
+ ranges = GetChapters(data, duration);
+ break;
+ default:
+ CLog::Log(LOGERROR, "CPlayerGUIInfo::GetContentRanges({}) - unhandled guiinfo", iInfo);
+ break;
+ }
+
+ // create csv string from ranges
+ for (const auto& range : ranges)
+ values += StringUtils::Format("{:.5f},{:.5f},", range.first, range.second);
+
+ if (!values.empty())
+ values.pop_back(); // remove trailing comma
+ }
+
+ return values;
+}
+
+std::vector<std::pair<float, float>> CPlayerGUIInfo::GetEditList(const CDataCacheCore& data,
+ std::time_t duration) const
+{
+ std::vector<std::pair<float, float>> ranges;
+
+ const std::vector<EDL::Edit>& edits = data.GetEditList();
+ for (const auto& edit : edits)
+ {
+ float editStart = edit.start * 100.0f / duration;
+ float editEnd = edit.end * 100.0f / duration;
+ ranges.emplace_back(std::make_pair(editStart, editEnd));
+ }
+ return ranges;
+}
+
+std::vector<std::pair<float, float>> CPlayerGUIInfo::GetCuts(const CDataCacheCore& data,
+ std::time_t duration) const
+{
+ std::vector<std::pair<float, float>> ranges;
+
+ const std::vector<int64_t>& cuts = data.GetCuts();
+ float lastMarker = 0.0f;
+ for (const auto& cut : cuts)
+ {
+ float marker = cut * 100.0f / duration;
+ if (marker != 0)
+ ranges.emplace_back(std::make_pair(lastMarker, marker));
+
+ lastMarker = marker;
+ }
+ return ranges;
+}
+
+std::vector<std::pair<float, float>> CPlayerGUIInfo::GetSceneMarkers(const CDataCacheCore& data,
+ std::time_t duration) const
+{
+ std::vector<std::pair<float, float>> ranges;
+
+ const std::vector<int64_t>& scenes = data.GetSceneMarkers();
+ float lastMarker = 0.0f;
+ for (const auto& scene : scenes)
+ {
+ float marker = scene * 100.0f / duration;
+ if (marker != 0)
+ ranges.emplace_back(std::make_pair(lastMarker, marker));
+
+ lastMarker = marker;
+ }
+ return ranges;
+}
+
+std::vector<std::pair<float, float>> CPlayerGUIInfo::GetChapters(const CDataCacheCore& data,
+ std::time_t duration) const
+{
+ std::vector<std::pair<float, float>> ranges;
+
+ const std::vector<std::pair<std::string, int64_t>>& chapters = data.GetChapters();
+ float lastMarker = 0.0f;
+ for (const auto& chapter : chapters)
+ {
+ float marker = chapter.second * 1000 * 100.0f / duration;
+ if (marker != 0)
+ ranges.emplace_back(std::make_pair(lastMarker, marker));
+
+ lastMarker = marker;
+ }
+ return ranges;
+}
diff --git a/xbmc/guilib/guiinfo/PlayerGUIInfo.h b/xbmc/guilib/guiinfo/PlayerGUIInfo.h
new file mode 100644
index 0000000..e0cb3c8
--- /dev/null
+++ b/xbmc/guilib/guiinfo/PlayerGUIInfo.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+#include "utils/EventStream.h"
+#include "utils/TimeFormat.h"
+
+#include <atomic>
+#include <ctime>
+#include <memory>
+#include <utility>
+#include <vector>
+
+class CApplicationPlayer;
+class CApplicationVolumeHandling;
+class CDataCacheCore;
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+struct PlayerShowInfoChangedEvent
+{
+ explicit PlayerShowInfoChangedEvent(bool showInfo) : m_showInfo(showInfo) {}
+ virtual ~PlayerShowInfoChangedEvent() = default;
+
+ bool m_showInfo{false};
+};
+
+class CPlayerGUIInfo : public CGUIInfoProvider
+{
+public:
+ CPlayerGUIInfo();
+ ~CPlayerGUIInfo() override;
+
+ CEventStream<PlayerShowInfoChangedEvent>& Events() { return m_events; }
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+
+ void SetShowTime(bool showtime) { m_playerShowTime = showtime; }
+ void SetShowInfo(bool showinfo);
+ bool GetShowInfo() const { return m_playerShowInfo; }
+ bool ToggleShowInfo();
+
+private:
+ int GetTotalPlayTime() const;
+ int GetPlayTime() const;
+ int GetPlayTimeRemaining() const;
+ float GetSeekPercent() const;
+
+ std::string GetCurrentPlayTime(TIME_FORMAT format) const;
+ std::string GetCurrentPlayTimeRemaining(TIME_FORMAT format) const;
+ std::string GetDuration(TIME_FORMAT format) const;
+ std::string GetCurrentSeekTime(TIME_FORMAT format) const;
+ std::string GetSeekTime(TIME_FORMAT format) const;
+
+ std::string GetContentRanges(int iInfo) const;
+ std::vector<std::pair<float, float>> GetEditList(const CDataCacheCore& data,
+ std::time_t duration) const;
+ std::vector<std::pair<float, float>> GetCuts(const CDataCacheCore& data,
+ std::time_t duration) const;
+ std::vector<std::pair<float, float>> GetSceneMarkers(const CDataCacheCore& data,
+ std::time_t duration) const;
+ std::vector<std::pair<float, float>> GetChapters(const CDataCacheCore& data,
+ std::time_t duration) const;
+
+ std::unique_ptr<CFileItem> m_currentItem;
+ std::atomic_bool m_playerShowTime{false};
+ std::atomic_bool m_playerShowInfo{false};
+ const std::shared_ptr<CApplicationPlayer> m_appPlayer;
+ const std::shared_ptr<CApplicationVolumeHandling> m_appVolume;
+ CEventSource<PlayerShowInfoChangedEvent> m_events;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/SkinGUIInfo.cpp b/xbmc/guilib/guiinfo/SkinGUIInfo.cpp
new file mode 100644
index 0000000..1d51b96
--- /dev/null
+++ b/xbmc/guilib/guiinfo/SkinGUIInfo.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/SkinGUIInfo.h"
+
+#include "ServiceBroker.h"
+#include "addons/Skin.h"
+#include "guilib/LocalizeStrings.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "settings/SkinSettings.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+
+using namespace KODI::GUILIB::GUIINFO;
+
+bool CSkinGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ return false;
+}
+
+bool CSkinGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SKIN_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SKIN_BOOL:
+ {
+ bool bInfo = CSkinSettings::GetInstance().GetBool(info.GetData1());
+ if (bInfo)
+ {
+ value = g_localizeStrings.Get(20122); // True
+ return true;
+ }
+ break;
+ }
+ case SKIN_STRING:
+ {
+ value = CSkinSettings::GetInstance().GetString(info.GetData1());
+ return true;
+ }
+ case SKIN_THEME:
+ {
+ value = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOOKANDFEEL_SKINTHEME);
+ return true;
+ }
+ case SKIN_COLOUR_THEME:
+ {
+ value = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOOKANDFEEL_SKINCOLORS);
+ return true;
+ }
+ case SKIN_ASPECT_RATIO:
+ {
+ if (g_SkinInfo)
+ {
+ value = g_SkinInfo->GetCurrentAspect();
+ return true;
+ }
+ break;
+ }
+ case SKIN_FONT:
+ {
+ value = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOOKANDFEEL_FONT);
+ return true;
+ }
+ case SKIN_TIMER_ELAPSEDSECS:
+ {
+ value = std::to_string(g_SkinInfo->GetTimerElapsedSeconds(info.GetData3()));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CSkinGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ case SKIN_INTEGER:
+ {
+ value = CSkinSettings::GetInstance().GetInt(info.GetData1());
+ return true;
+ }
+ case SKIN_TIMER_ELAPSEDSECS:
+ {
+ value = g_SkinInfo->GetTimerElapsedSeconds(info.GetData3());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CSkinGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SKIN_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SKIN_BOOL:
+ {
+ value = CSkinSettings::GetInstance().GetBool(info.GetData1());
+ return true;
+ }
+ case SKIN_STRING_IS_EQUAL:
+ {
+ value = StringUtils::EqualsNoCase(CSkinSettings::GetInstance().GetString(info.GetData1()), info.GetData3());
+ return true;
+ }
+ case SKIN_STRING:
+ {
+ value = !CSkinSettings::GetInstance().GetString(info.GetData1()).empty();
+ return true;
+ }
+ case SKIN_HAS_THEME:
+ {
+ std::string theme = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOOKANDFEEL_SKINTHEME);
+ URIUtils::RemoveExtension(theme);
+ value = StringUtils::EqualsNoCase(theme, info.GetData3());
+ return true;
+ }
+ case SKIN_TIMER_IS_RUNNING:
+ {
+ value = g_SkinInfo->TimerIsRunning(info.GetData3());
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/SkinGUIInfo.h b/xbmc/guilib/guiinfo/SkinGUIInfo.h
new file mode 100644
index 0000000..7f6c1c4
--- /dev/null
+++ b/xbmc/guilib/guiinfo/SkinGUIInfo.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CSkinGUIInfo : public CGUIInfoProvider
+{
+public:
+ CSkinGUIInfo() = default;
+ ~CSkinGUIInfo() override = default;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/SystemGUIInfo.cpp b/xbmc/guilib/guiinfo/SystemGUIInfo.cpp
new file mode 100644
index 0000000..bc01047
--- /dev/null
+++ b/xbmc/guilib/guiinfo/SystemGUIInfo.cpp
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/SystemGUIInfo.h"
+
+#include "FileItem.h"
+#include "GUIPassword.h"
+#include "LangInfo.h"
+#include "ServiceBroker.h"
+#include "addons/AddonManager.h"
+#include "addons/addoninfo/AddonType.h"
+#include "application/AppParams.h"
+#include "application/ApplicationComponents.h"
+#include "application/ApplicationPowerHandling.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "network/Network.h"
+#if defined(TARGET_DARWIN_OSX)
+#include "platform/darwin/osx/smc.h"
+#endif
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoHelper.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "powermanagement/PowerManager.h"
+#include "profiles/ProfileManager.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/MediaSettings.h"
+#include "settings/SettingUtils.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "storage/MediaManager.h"
+#include "storage/discs/IDiscDriveHandler.h"
+#include "utils/AlarmClock.h"
+#include "utils/CPUInfo.h"
+#include "utils/HDRCapabilities.h"
+#include "utils/MemUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/SystemInfo.h"
+#include "utils/TimeUtils.h"
+#include "windowing/WinSystem.h"
+#include "windows/GUIMediaWindow.h"
+
+using namespace KODI::GUILIB;
+using namespace KODI::GUILIB::GUIINFO;
+
+CSystemGUIInfo::CSystemGUIInfo()
+: m_lastSysHeatInfoTime(-SYSTEM_HEAT_UPDATE_INTERVAL)
+{
+}
+
+std::string CSystemGUIInfo::GetSystemHeatInfo(int info) const
+{
+ if (CTimeUtils::GetFrameTime() - m_lastSysHeatInfoTime >= SYSTEM_HEAT_UPDATE_INTERVAL)
+ {
+ m_lastSysHeatInfoTime = CTimeUtils::GetFrameTime();
+#if defined(TARGET_POSIX)
+ CServiceBroker::GetCPUInfo()->GetTemperature(m_cpuTemp);
+ m_gpuTemp = GetGPUTemperature();
+#endif
+ }
+
+ std::string text;
+ switch(info)
+ {
+ case SYSTEM_CPU_TEMPERATURE:
+ return m_cpuTemp.IsValid() ? g_langInfo.GetTemperatureAsString(m_cpuTemp) : g_localizeStrings.Get(10005); // Not available
+ case SYSTEM_GPU_TEMPERATURE:
+ return m_gpuTemp.IsValid() ? g_langInfo.GetTemperatureAsString(m_gpuTemp) : g_localizeStrings.Get(10005);
+ case SYSTEM_FAN_SPEED:
+ text = StringUtils::Format("{}%", m_fanSpeed * 2);
+ break;
+ case SYSTEM_CPU_USAGE:
+ if (CServiceBroker::GetCPUInfo()->SupportsCPUUsage())
+#if defined(TARGET_DARWIN) || defined(TARGET_WINDOWS)
+ text = StringUtils::Format("{}%", CServiceBroker::GetCPUInfo()->GetUsedPercentage());
+#else
+ text = CServiceBroker::GetCPUInfo()->GetCoresUsageString();
+#endif
+ else
+ text = g_localizeStrings.Get(10005); // Not available
+ break;
+ }
+ return text;
+}
+
+CTemperature CSystemGUIInfo::GetGPUTemperature() const
+{
+ int value = 0;
+ char scale = 0;
+
+#if defined(TARGET_DARWIN_OSX)
+ value = SMCGetTemperature(SMC_KEY_GPU_TEMP);
+ return CTemperature::CreateFromCelsius(value);
+#elif defined(TARGET_WINDOWS_STORE)
+ return CTemperature::CreateFromCelsius(0);
+#else
+ std::string cmd = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_gpuTempCmd;
+ int ret = 0;
+ FILE* p = NULL;
+
+ if (cmd.empty() || !(p = popen(cmd.c_str(), "r")))
+ return CTemperature();
+
+ ret = fscanf(p, "%d %c", &value, &scale);
+ pclose(p);
+
+ if (ret != 2)
+ return CTemperature();
+#endif
+
+ if (scale == 'C' || scale == 'c')
+ return CTemperature::CreateFromCelsius(value);
+ if (scale == 'F' || scale == 'f')
+ return CTemperature::CreateFromFahrenheit(value);
+ return CTemperature();
+}
+
+void CSystemGUIInfo::UpdateFPS()
+{
+ m_frameCounter++;
+ unsigned int curTime = CTimeUtils::GetFrameTime();
+
+ float fTimeSpan = static_cast<float>(curTime - m_lastFPSTime);
+ if (fTimeSpan >= 1000.0f)
+ {
+ fTimeSpan /= 1000.0f;
+ m_fps = m_frameCounter / fTimeSpan;
+ m_lastFPSTime = curTime;
+ m_frameCounter = 0;
+ }
+}
+
+bool CSystemGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ return false;
+}
+
+bool CSystemGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SYSTEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SYSTEM_TIME:
+ value = CDateTime::GetCurrentDateTime().GetAsLocalizedTime(static_cast<TIME_FORMAT>(info.GetData1()));
+ return true;
+ case SYSTEM_DATE:
+ if (info.GetData3().empty())
+ value = CDateTime::GetCurrentDateTime().GetAsLocalizedDate(true);
+ else
+ value = CDateTime::GetCurrentDateTime().GetAsLocalizedDate(info.GetData3());
+ return true;
+ case SYSTEM_FREE_SPACE:
+ case SYSTEM_USED_SPACE:
+ case SYSTEM_TOTAL_SPACE:
+ case SYSTEM_FREE_SPACE_PERCENT:
+ case SYSTEM_USED_SPACE_PERCENT:
+ value = g_sysinfo.GetHddSpaceInfo(info.m_info);
+ return true;
+ case SYSTEM_CPU_TEMPERATURE:
+ case SYSTEM_GPU_TEMPERATURE:
+ case SYSTEM_FAN_SPEED:
+ case SYSTEM_CPU_USAGE:
+ value = GetSystemHeatInfo(info.m_info);
+ return true;
+ case SYSTEM_VIDEO_ENCODER_INFO:
+ case NETWORK_MAC_ADDRESS:
+ case SYSTEM_OS_VERSION_INFO:
+ case SYSTEM_CPUFREQUENCY:
+ case SYSTEM_INTERNET_STATE:
+ case SYSTEM_UPTIME:
+ case SYSTEM_TOTALUPTIME:
+ case SYSTEM_BATTERY_LEVEL:
+ value = g_sysinfo.GetInfo(info.m_info);
+ return true;
+ case SYSTEM_PRIVACY_POLICY:
+ value = g_sysinfo.GetPrivacyPolicy();
+ return true;
+ case SYSTEM_SCREEN_RESOLUTION:
+ {
+ const auto winSystem = CServiceBroker::GetWinSystem();
+ if (winSystem)
+ {
+ const RESOLUTION_INFO& resInfo = winSystem->GetGfxContext().GetResInfo();
+
+ if (winSystem->IsFullScreen())
+ value = StringUtils::Format("{}x{} @ {:.2f} Hz - {}", resInfo.iScreenWidth,
+ resInfo.iScreenHeight, resInfo.fRefreshRate,
+ g_localizeStrings.Get(244));
+ else
+ value = StringUtils::Format("{}x{} - {}", resInfo.iScreenWidth, resInfo.iScreenHeight,
+ g_localizeStrings.Get(242));
+ }
+ else
+ {
+ value = "";
+ }
+ return true;
+ }
+ case SYSTEM_BUILD_VERSION_SHORT:
+ value = CSysInfo::GetVersionShort();
+ return true;
+ case SYSTEM_BUILD_VERSION:
+ value = CSysInfo::GetVersion();
+ return true;
+ case SYSTEM_BUILD_DATE:
+ value = CSysInfo::GetBuildDate();
+ return true;
+ case SYSTEM_BUILD_VERSION_CODE:
+ value = CSysInfo::GetVersionCode();
+ return true;
+ case SYSTEM_BUILD_VERSION_GIT:
+ value = CSysInfo::GetVersionGit();
+ return true;
+ case SYSTEM_FREE_MEMORY:
+ case SYSTEM_FREE_MEMORY_PERCENT:
+ case SYSTEM_USED_MEMORY:
+ case SYSTEM_USED_MEMORY_PERCENT:
+ case SYSTEM_TOTAL_MEMORY:
+ {
+ KODI::MEMORY::MemoryStatus stat;
+ KODI::MEMORY::GetMemoryStatus(&stat);
+ int iMemPercentFree = 100 - static_cast<int>(100.0f * (stat.totalPhys - stat.availPhys) / stat.totalPhys + 0.5f);
+ int iMemPercentUsed = 100 - iMemPercentFree;
+
+ if (info.m_info == SYSTEM_FREE_MEMORY)
+ value = StringUtils::Format("{}MB", static_cast<unsigned int>(stat.availPhys / MB));
+ else if (info.m_info == SYSTEM_FREE_MEMORY_PERCENT)
+ value = StringUtils::Format("{}%", iMemPercentFree);
+ else if (info.m_info == SYSTEM_USED_MEMORY)
+ value = StringUtils::Format(
+ "{}MB", static_cast<unsigned int>((stat.totalPhys - stat.availPhys) / MB));
+ else if (info.m_info == SYSTEM_USED_MEMORY_PERCENT)
+ value = StringUtils::Format("{}%", iMemPercentUsed);
+ else if (info.m_info == SYSTEM_TOTAL_MEMORY)
+ value = StringUtils::Format("{}MB", static_cast<unsigned int>(stat.totalPhys / MB));
+ return true;
+ }
+ case SYSTEM_SCREEN_MODE:
+ value = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo().strMode;
+ return true;
+ case SYSTEM_SCREEN_WIDTH:
+ value = StringUtils::Format(
+ "{}", CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo().iScreenWidth);
+ return true;
+ case SYSTEM_SCREEN_HEIGHT:
+ value = StringUtils::Format(
+ "{}", CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo().iScreenHeight);
+ return true;
+ case SYSTEM_FPS:
+ value = StringUtils::Format("{:02.2f}", m_fps);
+ return true;
+#ifdef HAS_DVD_DRIVE
+ case SYSTEM_DVD_LABEL:
+ value = CServiceBroker::GetMediaManager().GetDiskLabel();
+ return true;
+#endif
+ case SYSTEM_ALARM_POS:
+ if (g_alarmClock.GetRemaining("shutdowntimer") == 0.0)
+ value.clear();
+ else
+ {
+ double fTime = g_alarmClock.GetRemaining("shutdowntimer");
+ if (fTime > 60.0)
+ value = StringUtils::Format(g_localizeStrings.Get(13213),
+ g_alarmClock.GetRemaining("shutdowntimer") / 60.0);
+ else
+ value = StringUtils::Format(g_localizeStrings.Get(13214),
+ g_alarmClock.GetRemaining("shutdowntimer"));
+ }
+ return true;
+ case SYSTEM_PROFILENAME:
+ value = CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetCurrentProfile().getName();
+ return true;
+ case SYSTEM_PROFILECOUNT:
+ value = StringUtils::Format("{0}", CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetNumberOfProfiles());
+ return true;
+ case SYSTEM_PROFILEAUTOLOGIN:
+ {
+ const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();
+ int iProfileId = profileManager->GetAutoLoginProfileId();
+ if ((iProfileId < 0) || !profileManager->GetProfileName(iProfileId, value))
+ value = g_localizeStrings.Get(37014); // Last used profile
+ return true;
+ }
+ case SYSTEM_PROFILETHUMB:
+ {
+ const std::string& thumb = CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetCurrentProfile().getThumb();
+ value = thumb.empty() ? "DefaultUser.png" : thumb;
+ return true;
+ }
+ case SYSTEM_LANGUAGE:
+ value = g_langInfo.GetEnglishLanguageName();
+ return true;
+ case SYSTEM_TEMPERATURE_UNITS:
+ value = g_langInfo.GetTemperatureUnitString();
+ return true;
+ case SYSTEM_FRIENDLY_NAME:
+ value = CSysInfo::GetDeviceName();
+ return true;
+ case SYSTEM_STEREOSCOPIC_MODE:
+ {
+ int iStereoMode = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOSCREEN_STEREOSCOPICMODE);
+ value = std::to_string(iStereoMode);
+ return true;
+ }
+ case SYSTEM_GET_CORE_USAGE:
+ value = StringUtils::Format(
+ "{:4.2f}",
+ CServiceBroker::GetCPUInfo()->GetCoreInfo(std::stoi(info.GetData3())).m_usagePercent);
+ return true;
+ case SYSTEM_RENDER_VENDOR:
+ value = CServiceBroker::GetRenderSystem()->GetRenderVendor();
+ return true;
+ case SYSTEM_RENDER_RENDERER:
+ value = CServiceBroker::GetRenderSystem()->GetRenderRenderer();
+ return true;
+ case SYSTEM_RENDER_VERSION:
+ value = CServiceBroker::GetRenderSystem()->GetRenderVersionString();
+ return true;
+ case SYSTEM_ADDON_UPDATE_COUNT:
+ value = CServiceBroker::GetAddonMgr().GetLastAvailableUpdatesCountAsString();
+ return true;
+#if defined(TARGET_LINUX)
+ case SYSTEM_PLATFORM_WINDOWING:
+ value = CServiceBroker::GetWinSystem()->GetName();
+ StringUtils::ToCapitalize(value);
+ return true;
+#endif
+ case SYSTEM_SUPPORTED_HDR_TYPES:
+ {
+ if (CServiceBroker::GetWinSystem()->IsHDRDisplay())
+ {
+ // Assumes HDR10 minimum requirement for HDR
+ std::string types = "HDR10";
+
+ const CHDRCapabilities caps = CServiceBroker::GetWinSystem()->GetDisplayHDRCapabilities();
+
+ if (caps.SupportsHLG())
+ types += ", HLG";
+ if (caps.SupportsHDR10Plus())
+ types += ", HDR10+";
+ if (caps.SupportsDolbyVision())
+ types += ", Dolby Vision";
+
+ value = types;
+ }
+
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // NETWORK_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case NETWORK_IP_ADDRESS:
+ {
+ CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface();
+ if (iface)
+ {
+ value = iface->GetCurrentIPAddress();
+ return true;
+ }
+ break;
+ }
+ case NETWORK_SUBNET_MASK:
+ {
+ CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface();
+ if (iface)
+ {
+ value = iface->GetCurrentNetmask();
+ return true;
+ }
+ break;
+ }
+ case NETWORK_GATEWAY_ADDRESS:
+ {
+ CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface();
+ if (iface)
+ {
+ value = iface->GetCurrentDefaultGateway();
+ return true;
+ }
+ break;
+ }
+ case NETWORK_DNS1_ADDRESS:
+ {
+ const std::vector<std::string> nss = CServiceBroker::GetNetwork().GetNameServers();
+ if (nss.size() >= 1)
+ {
+ value = nss[0];
+ return true;
+ }
+ break;
+ }
+ case NETWORK_DNS2_ADDRESS:
+ {
+ const std::vector<std::string> nss = CServiceBroker::GetNetwork().GetNameServers();
+ if (nss.size() >= 2)
+ {
+ value = nss[1];
+ return true;
+ }
+ break;
+ }
+ case NETWORK_DHCP_ADDRESS:
+ {
+ // wtf?
+ std::string dhcpserver;
+ value = dhcpserver;
+ return true;
+ }
+ case NETWORK_LINK_STATE:
+ {
+ std::string linkStatus = g_localizeStrings.Get(151);
+ linkStatus += " ";
+ CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface();
+ if (iface && iface->IsConnected())
+ linkStatus += g_localizeStrings.Get(15207);
+ else
+ linkStatus += g_localizeStrings.Get(15208);
+ value = linkStatus;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CSystemGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SYSTEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SYSTEM_FREE_MEMORY:
+ case SYSTEM_USED_MEMORY:
+ {
+ KODI::MEMORY::MemoryStatus stat;
+ KODI::MEMORY::GetMemoryStatus(&stat);
+ int memPercentUsed = static_cast<int>(100.0f * (stat.totalPhys - stat.availPhys) / stat.totalPhys + 0.5f);
+ if (info.m_info == SYSTEM_FREE_MEMORY)
+ value = 100 - memPercentUsed;
+ else
+ value = memPercentUsed;
+ return true;
+ }
+ case SYSTEM_FREE_SPACE:
+ case SYSTEM_USED_SPACE:
+ {
+ g_sysinfo.GetHddSpaceInfo(value, info.m_info, true);
+ return true;
+ }
+ case SYSTEM_CPU_USAGE:
+ value = CServiceBroker::GetCPUInfo()->GetUsedPercentage();
+ return true;
+ case SYSTEM_BATTERY_LEVEL:
+ value = CServiceBroker::GetPowerManager().BatteryLevel();
+ return true;
+ }
+
+ return false;
+}
+
+bool CSystemGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SYSTEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case SYSTEM_ALWAYS_TRUE:
+ value = true;
+ return true;
+ case SYSTEM_ALWAYS_FALSE:
+ value = false;
+ return true;
+ case SYSTEM_ETHERNET_LINK_ACTIVE:
+ // wtf: not implemented - always returns true?!
+ value = true;
+ return true;
+ case SYSTEM_PLATFORM_LINUX:
+#if defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
+ value = true;
+#else
+ value = false;
+#endif
+ return true;
+ case SYSTEM_PLATFORM_WINDOWS:
+#ifdef TARGET_WINDOWS
+ value = true;
+#else
+ value = false;
+#endif
+ return true;
+ case SYSTEM_PLATFORM_UWP:
+#ifdef TARGET_WINDOWS_STORE
+ value = true;
+#else
+ value = false;
+#endif
+ return true;
+ case SYSTEM_PLATFORM_DARWIN:
+#ifdef TARGET_DARWIN
+ value = true;
+#else
+ value = false;
+#endif
+ return true;
+ case SYSTEM_PLATFORM_DARWIN_OSX:
+#ifdef TARGET_DARWIN_OSX
+ value = true;
+#else
+ value = false;
+#endif
+ return true;
+ case SYSTEM_PLATFORM_DARWIN_IOS:
+#ifdef TARGET_DARWIN_IOS
+ value = true;
+#else
+ value = false;
+#endif
+ return true;
+ case SYSTEM_PLATFORM_DARWIN_TVOS:
+#ifdef TARGET_DARWIN_TVOS
+ value = true;
+#else
+ value = false;
+#endif
+ return true;
+ case SYSTEM_PLATFORM_ANDROID:
+#if defined(TARGET_ANDROID)
+ value = true;
+#else
+ value = false;
+#endif
+ return true;
+ case SYSTEM_MEDIA_DVD:
+ value = CServiceBroker::GetMediaManager().IsDiscInDrive();
+ return true;
+ case SYSTEM_MEDIA_AUDIO_CD:
+ #ifdef HAS_DVD_DRIVE
+ if (CServiceBroker::GetMediaManager().IsDiscInDrive())
+ {
+ MEDIA_DETECT::CCdInfo* pCdInfo = CServiceBroker::GetMediaManager().GetCdInfo();
+ value = pCdInfo && (pCdInfo->IsAudio(1) || pCdInfo->IsCDExtra(1) || pCdInfo->IsMixedMode(1));
+ }
+ else
+ #endif
+ {
+ value = false;
+ }
+ return true;
+#ifdef HAS_DVD_DRIVE
+ case SYSTEM_DVDREADY:
+ value = CServiceBroker::GetMediaManager().GetDriveStatus() != DriveState::NOT_READY;
+ return true;
+ case SYSTEM_TRAYOPEN:
+ value = CServiceBroker::GetMediaManager().GetDriveStatus() == DriveState::OPEN;
+ return true;
+#endif
+ case SYSTEM_CAN_POWERDOWN:
+ value = CServiceBroker::GetPowerManager().CanPowerdown();
+ return true;
+ case SYSTEM_CAN_SUSPEND:
+ value = CServiceBroker::GetPowerManager().CanSuspend();
+ return true;
+ case SYSTEM_CAN_HIBERNATE:
+ value = CServiceBroker::GetPowerManager().CanHibernate();
+ return true;
+ case SYSTEM_CAN_REBOOT:
+ value = CServiceBroker::GetPowerManager().CanReboot();
+ return true;
+ case SYSTEM_SCREENSAVER_ACTIVE:
+ case SYSTEM_IS_SCREENSAVER_INHIBITED:
+ case SYSTEM_DPMS_ACTIVE:
+ case SYSTEM_IDLE_SHUTDOWN_INHIBITED:
+ case SYSTEM_IDLE_TIME:
+ {
+ auto& components = CServiceBroker::GetAppComponents();
+ const auto appPower = components.GetComponent<CApplicationPowerHandling>();
+ switch (info.m_info)
+ {
+ case SYSTEM_SCREENSAVER_ACTIVE:
+ value = appPower->IsInScreenSaver();
+ return true;
+ case SYSTEM_IS_SCREENSAVER_INHIBITED:
+ value = appPower->IsScreenSaverInhibited();
+ return true;
+ case SYSTEM_DPMS_ACTIVE:
+ value = appPower->IsDPMSActive();
+ return true;
+ case SYSTEM_IDLE_SHUTDOWN_INHIBITED:
+ value = appPower->IsIdleShutdownInhibited();
+ return true;
+ case SYSTEM_IDLE_TIME:
+ value = appPower->GlobalIdleTime() >= static_cast<int>(info.GetData1());
+ return true;
+ default:
+ return false;
+ }
+ }
+ case SYSTEM_HASLOCKS:
+ value = CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE;
+ return true;
+ case SYSTEM_HAS_PVR:
+ value = true;
+ return true;
+ case SYSTEM_HAS_PVR_ADDON:
+ value = CServiceBroker::GetAddonMgr().HasAddons(ADDON::AddonType::PVRDLL);
+ return true;
+ case SYSTEM_HAS_CMS:
+#if defined(HAS_GL) || defined(HAS_DX)
+ value = true;
+#else
+ value = false;
+#endif
+ return true;
+ case SYSTEM_ISMASTER:
+ value = CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && g_passwordManager.bMasterUser;
+ return true;
+ case SYSTEM_ISFULLSCREEN:
+ value = CServiceBroker::GetWinSystem()->IsFullScreen();
+ return true;
+ case SYSTEM_ISSTANDALONE:
+ value = CServiceBroker::GetAppParams()->IsStandAlone();
+ return true;
+ case SYSTEM_HAS_SHUTDOWN:
+ value = (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNTIME) > 0);
+ return true;
+ case SYSTEM_LOGGEDON:
+ value = !(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_LOGIN_SCREEN);
+ return true;
+ case SYSTEM_SHOW_EXIT_BUTTON:
+ value = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_showExitButton;
+ return true;
+ case SYSTEM_HAS_LOGINSCREEN:
+ value = CServiceBroker::GetSettingsComponent()->GetProfileManager()->UsingLoginScreen();
+ return true;
+ case SYSTEM_INTERNET_STATE:
+ {
+ g_sysinfo.GetInfo(info.m_info);
+ value = g_sysinfo.HasInternet();
+ return true;
+ }
+ case SYSTEM_HAS_CORE_ID:
+ value = CServiceBroker::GetCPUInfo()->HasCoreId(info.GetData1());
+ return true;
+ case SYSTEM_DATE:
+ {
+ if (info.GetData2() == -1) // info doesn't contain valid startDate
+ return false;
+ const CDateTime date = CDateTime::GetCurrentDateTime();
+ int currentDate = date.GetMonth() * 100 + date.GetDay();
+ int startDate = info.GetData1();
+ int stopDate = info.GetData2();
+
+ if (stopDate < startDate)
+ value = currentDate >= startDate || currentDate < stopDate;
+ else
+ value = currentDate >= startDate && currentDate < stopDate;
+ return true;
+ }
+ case SYSTEM_TIME:
+ {
+ int currentTime = CDateTime::GetCurrentDateTime().GetMinuteOfDay();
+ int startTime = info.GetData1();
+ int stopTime = info.GetData2();
+
+ if (stopTime < startTime)
+ value = currentTime >= startTime || currentTime < stopTime;
+ else
+ value = currentTime >= startTime && currentTime < stopTime;
+ return true;
+ }
+ case SYSTEM_ALARM_LESS_OR_EQUAL:
+ {
+ int time = std::lrint(g_alarmClock.GetRemaining(info.GetData3()));
+ int timeCompare = info.GetData2();
+ if (time > 0)
+ value = timeCompare >= time;
+ else
+ value = false;
+ return true;
+ }
+ case SYSTEM_HAS_ALARM:
+ value = g_alarmClock.HasAlarm(info.GetData3());
+ return true;
+ case SYSTEM_SUPPORTS_CPU_USAGE:
+ value = CServiceBroker::GetCPUInfo()->SupportsCPUUsage();
+ return true;
+ case SYSTEM_GET_BOOL:
+ value = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(info.GetData3());
+ return true;
+ case SYSTEM_SETTING:
+ {
+ if (StringUtils::EqualsNoCase(info.GetData3(), "hidewatched"))
+ {
+ CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow);
+ if (window)
+ {
+ value = CMediaSettings::GetInstance().GetWatchedMode(window->CurrentDirectory().GetContent()) == WatchedModeUnwatched;
+ return true;
+ }
+ }
+ else if (StringUtils::EqualsNoCase(info.GetData3(), "hideunwatchedepisodethumbs"))
+ {
+ const std::shared_ptr<CSettingList> setting(std::dynamic_pointer_cast<CSettingList>(
+ CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(
+ CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS)));
+ value = setting && !CSettingUtils::FindIntInList(
+ setting, CSettings::VIDEOLIBRARY_THUMB_SHOW_UNWATCHED_EPISODE);
+ return true;
+ }
+ break;
+ }
+ }
+
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/SystemGUIInfo.h b/xbmc/guilib/guiinfo/SystemGUIInfo.h
new file mode 100644
index 0000000..ed2ea03
--- /dev/null
+++ b/xbmc/guilib/guiinfo/SystemGUIInfo.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+#include "utils/Temperature.h"
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CSystemGUIInfo : public CGUIInfoProvider
+{
+public:
+ CSystemGUIInfo();
+ ~CSystemGUIInfo() override = default;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+
+ float GetFPS() const { return m_fps; }
+ void UpdateFPS();
+
+private:
+ std::string GetSystemHeatInfo(int info) const;
+ CTemperature GetGPUTemperature() const;
+
+ static const int SYSTEM_HEAT_UPDATE_INTERVAL = 60000;
+
+ mutable unsigned int m_lastSysHeatInfoTime;
+ mutable CTemperature m_gpuTemp;
+ mutable CTemperature m_cpuTemp;
+ int m_fanSpeed = 0;
+ float m_fps = 0.0;
+ unsigned int m_frameCounter = 0;
+ unsigned int m_lastFPSTime = 0;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/VideoGUIInfo.cpp b/xbmc/guilib/guiinfo/VideoGUIInfo.cpp
new file mode 100644
index 0000000..794434f
--- /dev/null
+++ b/xbmc/guilib/guiinfo/VideoGUIInfo.cpp
@@ -0,0 +1,818 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/VideoGUIInfo.h"
+
+#include "FileItem.h"
+#include "PlayListPlayer.h"
+#include "ServiceBroker.h"
+#include "URL.h"
+#include "Util.h"
+#include "application/Application.h"
+#include "application/ApplicationComponents.h"
+#include "application/ApplicationPlayer.h"
+#include "cores/DataCacheCore.h"
+#include "cores/VideoPlayer/VideoRenderers/BaseRenderer.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "guilib/StereoscopicsManager.h"
+#include "guilib/WindowIDs.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoHelper.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "playlists/PlayList.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/SettingUtils.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "settings/lib/Setting.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+#include "utils/log.h"
+#include "video/VideoInfoTag.h"
+#include "video/VideoThumbLoader.h"
+
+#include <math.h>
+
+using namespace KODI::GUILIB;
+using namespace KODI::GUILIB::GUIINFO;
+
+CVideoGUIInfo::CVideoGUIInfo()
+ : m_appPlayer(CServiceBroker::GetAppComponents().GetComponent<CApplicationPlayer>())
+{
+}
+
+int CVideoGUIInfo::GetPercentPlayed(const CVideoInfoTag* tag) const
+{
+ CBookmark bookmark = tag->GetResumePoint();
+ if (bookmark.IsPartWay())
+ return std::lrintf(static_cast<float>(bookmark.timeInSeconds) /
+ static_cast<float>(bookmark.totalTimeInSeconds) * 100.0f);
+ else
+ return 0;
+}
+
+bool CVideoGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ if (item && item->IsVideo())
+ {
+ // special case where .strm is used to start an audio stream
+ if (item->IsInternetStream() && m_appPlayer->IsPlayingAudio())
+ return false;
+
+ CLog::Log(LOGDEBUG, "CVideoGUIInfo::InitCurrentItem({})", CURL::GetRedacted(item->GetPath()));
+
+ // Find a thumb for this file.
+ if (!item->HasArt("thumb"))
+ {
+ CVideoThumbLoader loader;
+ loader.LoadItem(item);
+ }
+
+ // find a thumb for this stream
+ if (item->IsInternetStream())
+ {
+ if (!g_application.m_strPlayListFile.empty())
+ {
+ CLog::Log(LOGDEBUG, "Streaming media detected... using {} to find a thumb",
+ g_application.m_strPlayListFile);
+ CFileItem thumbItem(g_application.m_strPlayListFile,false);
+
+ CVideoThumbLoader loader;
+ if (loader.FillThumb(thumbItem))
+ item->SetArt("thumb", thumbItem.GetArt("thumb"));
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool CVideoGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ // For videoplayer "offset" and "position" info labels check playlist
+ if (info.GetData1() && ((info.m_info >= VIDEOPLAYER_OFFSET_POSITION_FIRST &&
+ info.m_info <= VIDEOPLAYER_OFFSET_POSITION_LAST) ||
+ (info.m_info >= PLAYER_OFFSET_POSITION_FIRST && info.m_info <= PLAYER_OFFSET_POSITION_LAST)))
+ return GetPlaylistInfo(value, info);
+
+ const CVideoInfoTag* tag = item->GetVideoInfoTag();
+ if (tag)
+ {
+ switch (info.m_info)
+ {
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // PLAYER_* / VIDEOPLAYER_* / LISTITEM_*
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ case VIDEOPLAYER_ART:
+ value = item->GetArt(info.GetData3());
+ return true;
+ case PLAYER_PATH:
+ case PLAYER_FILENAME:
+ case PLAYER_FILEPATH:
+ if (item->HasMusicInfoTag()) // special handling for music videos, which have both a videotag and a musictag
+ break;
+
+ value = tag->m_strFileNameAndPath;
+ if (value.empty())
+ value = item->GetPath();
+ value = GUIINFO::GetFileInfoLabelValueFromPath(info.m_info, value);
+ return true;
+ case PLAYER_TITLE:
+ value = tag->m_strTitle;
+ return !value.empty();
+ case VIDEOPLAYER_TITLE:
+ value = tag->m_strTitle;
+ return !value.empty();
+ case LISTITEM_TITLE:
+ value = tag->m_strTitle;
+ return true;
+ case VIDEOPLAYER_ORIGINALTITLE:
+ case LISTITEM_ORIGINALTITLE:
+ value = tag->m_strOriginalTitle;
+ return true;
+ case VIDEOPLAYER_GENRE:
+ case LISTITEM_GENRE:
+ value = StringUtils::Join(tag->m_genre, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ return true;
+ case VIDEOPLAYER_DIRECTOR:
+ case LISTITEM_DIRECTOR:
+ value = StringUtils::Join(tag->m_director, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ return true;
+ case VIDEOPLAYER_IMDBNUMBER:
+ case LISTITEM_IMDBNUMBER:
+ value = tag->GetUniqueID();
+ return true;
+ case VIDEOPLAYER_DBID:
+ case LISTITEM_DBID:
+ if (tag->m_iDbId > -1)
+ {
+ value = std::to_string(tag->m_iDbId);
+ return true;
+ }
+ break;
+ case VIDEOPLAYER_TVSHOWDBID:
+ case LISTITEM_TVSHOWDBID:
+ if (tag->m_iIdShow > -1)
+ {
+ value = std::to_string(tag->m_iIdShow);
+ return true;
+ }
+ break;
+ case VIDEOPLAYER_UNIQUEID:
+ case LISTITEM_UNIQUEID:
+ if (!info.GetData3().empty())
+ value = tag->GetUniqueID(info.GetData3());
+ return true;
+ case VIDEOPLAYER_RATING:
+ case LISTITEM_RATING:
+ {
+ float rating = tag->GetRating(info.GetData3()).rating;
+ if (rating > 0.f)
+ {
+ value = StringUtils::FormatNumber(rating);
+ return true;
+ }
+ break;
+ }
+ case VIDEOPLAYER_RATING_AND_VOTES:
+ case LISTITEM_RATING_AND_VOTES:
+ {
+ CRating rating = tag->GetRating(info.GetData3());
+ if (rating.rating >= 0.f)
+ {
+ if (rating.rating > 0.f && rating.votes == 0)
+ value = StringUtils::FormatNumber(rating.rating);
+ else if (rating.votes > 0)
+ value = StringUtils::Format(g_localizeStrings.Get(20350),
+ StringUtils::FormatNumber(rating.rating),
+ StringUtils::FormatNumber(rating.votes));
+ else
+ break;
+ return true;
+ }
+ break;
+ }
+ case VIDEOPLAYER_USER_RATING:
+ case LISTITEM_USER_RATING:
+ if (tag->m_iUserRating > 0)
+ {
+ value = std::to_string(tag->m_iUserRating);
+ return true;
+ }
+ break;
+ case VIDEOPLAYER_VOTES:
+ case LISTITEM_VOTES:
+ value = StringUtils::FormatNumber(tag->GetRating(info.GetData3()).votes);
+ return true;
+ case VIDEOPLAYER_YEAR:
+ case LISTITEM_YEAR:
+ if (tag->HasYear())
+ {
+ value = std::to_string(tag->GetYear());
+ return true;
+ }
+ break;
+ case VIDEOPLAYER_PREMIERED:
+ case LISTITEM_PREMIERED:
+ {
+ CDateTime dateTime;
+ if (tag->m_firstAired.IsValid())
+ dateTime = tag->m_firstAired;
+ else if (tag->HasPremiered())
+ dateTime = tag->GetPremiered();
+
+ if (dateTime.IsValid())
+ {
+ value = dateTime.GetAsLocalizedDate();
+ return true;
+ }
+ break;
+ }
+ case VIDEOPLAYER_PLOT:
+ value = tag->m_strPlot;
+ return true;
+ case VIDEOPLAYER_TRAILER:
+ case LISTITEM_TRAILER:
+ value = tag->m_strTrailer;
+ return true;
+ case VIDEOPLAYER_PLOT_OUTLINE:
+ case LISTITEM_PLOT_OUTLINE:
+ value = tag->m_strPlotOutline;
+ return true;
+ case VIDEOPLAYER_EPISODE:
+ case LISTITEM_EPISODE:
+ {
+ int iEpisode = -1;
+ if (tag->m_iEpisode > 0)
+ {
+ iEpisode = tag->m_iEpisode;
+ }
+
+ if (iEpisode >= 0)
+ {
+ value = std::to_string(iEpisode);
+ return true;
+ }
+ break;
+ }
+ case VIDEOPLAYER_SEASON:
+ case LISTITEM_SEASON:
+ if (tag->m_iSeason >= 0)
+ {
+ value = std::to_string(tag->m_iSeason);
+ return true;
+ }
+ break;
+ case VIDEOPLAYER_TVSHOW:
+ case LISTITEM_TVSHOW:
+ value = tag->m_strShowTitle;
+ return true;
+ case VIDEOPLAYER_STUDIO:
+ case LISTITEM_STUDIO:
+ value = StringUtils::Join(tag->m_studio, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ return true;
+ case VIDEOPLAYER_COUNTRY:
+ case LISTITEM_COUNTRY:
+ value = StringUtils::Join(tag->m_country, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ return true;
+ case VIDEOPLAYER_MPAA:
+ case LISTITEM_MPAA:
+ value = tag->m_strMPAARating;
+ return true;
+ case VIDEOPLAYER_TOP250:
+ case LISTITEM_TOP250:
+ if (tag->m_iTop250 > 0)
+ {
+ value = std::to_string(tag->m_iTop250);
+ return true;
+ }
+ break;
+ case VIDEOPLAYER_CAST:
+ case LISTITEM_CAST:
+ value = tag->GetCast();
+ return true;
+ case VIDEOPLAYER_CAST_AND_ROLE:
+ case LISTITEM_CAST_AND_ROLE:
+ value = tag->GetCast(true);
+ return true;
+ case VIDEOPLAYER_ARTIST:
+ case LISTITEM_ARTIST:
+ value = StringUtils::Join(tag->m_artist, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ return true;
+ case VIDEOPLAYER_ALBUM:
+ case LISTITEM_ALBUM:
+ value = tag->m_strAlbum;
+ return true;
+ case VIDEOPLAYER_WRITER:
+ case LISTITEM_WRITER:
+ value = StringUtils::Join(tag->m_writingCredits, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ return true;
+ case VIDEOPLAYER_TAGLINE:
+ case LISTITEM_TAGLINE:
+ value = tag->m_strTagLine;
+ return true;
+ case VIDEOPLAYER_LASTPLAYED:
+ case LISTITEM_LASTPLAYED:
+ {
+ const CDateTime dateTime = tag->m_lastPlayed;
+ if (dateTime.IsValid())
+ {
+ value = dateTime.GetAsLocalizedDate();
+ return true;
+ }
+ break;
+ }
+ case VIDEOPLAYER_PLAYCOUNT:
+ case LISTITEM_PLAYCOUNT:
+ if (tag->GetPlayCount() > 0)
+ {
+ value = std::to_string(tag->GetPlayCount());
+ return true;
+ }
+ break;
+
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ case LISTITEM_DURATION:
+ {
+ int iDuration = tag->GetDuration();
+ if (iDuration > 0)
+ {
+ value = StringUtils::SecondsToTimeString(iDuration, static_cast<TIME_FORMAT>(info.GetData4()));
+ return true;
+ }
+ break;
+ }
+ case LISTITEM_TRACKNUMBER:
+ if (tag->m_iTrack > -1 )
+ {
+ value = std::to_string(tag->m_iTrack);
+ return true;
+ }
+ break;
+ case LISTITEM_PLOT:
+ {
+ std::shared_ptr<CSettingList> setting(std::dynamic_pointer_cast<CSettingList>(
+ CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(
+ CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS)));
+ if (tag->m_type != MediaTypeTvShow && tag->m_type != MediaTypeVideoCollection &&
+ tag->GetPlayCount() == 0 && setting &&
+ ((tag->m_type == MediaTypeMovie &&
+ !CSettingUtils::FindIntInList(
+ setting, CSettings::VIDEOLIBRARY_PLOTS_SHOW_UNWATCHED_MOVIES)) ||
+ (tag->m_type == MediaTypeEpisode &&
+ !CSettingUtils::FindIntInList(
+ setting, CSettings::VIDEOLIBRARY_PLOTS_SHOW_UNWATCHED_TVSHOWEPISODES))))
+ {
+ value = g_localizeStrings.Get(20370);
+ }
+ else
+ {
+ value = tag->m_strPlot;
+ }
+ return true;
+ }
+ case LISTITEM_STATUS:
+ value = tag->m_strStatus;
+ return true;
+ case LISTITEM_TAG:
+ value = StringUtils::Join(tag->m_tags, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ return true;
+ case LISTITEM_SET:
+ value = tag->m_set.title;
+ return true;
+ case LISTITEM_SETID:
+ if (tag->m_set.id > 0)
+ {
+ value = std::to_string(tag->m_set.id);
+ return true;
+ }
+ break;
+ case LISTITEM_ENDTIME_RESUME:
+ {
+ const CDateTimeSpan duration(0, 0, 0, tag->GetDuration() - tag->GetResumePoint().timeInSeconds);
+ value = (CDateTime::GetCurrentDateTime() + duration).GetAsLocalizedTime("", false);
+ return true;
+ }
+ case LISTITEM_ENDTIME:
+ {
+ const CDateTimeSpan duration(0, 0, 0, tag->GetDuration());
+ value = (CDateTime::GetCurrentDateTime() + duration).GetAsLocalizedTime("", false);
+ return true;
+ }
+ case LISTITEM_DATE_ADDED:
+ if (tag->m_dateAdded.IsValid())
+ {
+ value = tag->m_dateAdded.GetAsLocalizedDate();
+ return true;
+ }
+ break;
+ case LISTITEM_DBTYPE:
+ value = tag->m_type;
+ return true;
+ case LISTITEM_APPEARANCES:
+ if (tag->m_relevance > -1)
+ {
+ value = std::to_string(tag->m_relevance);
+ return true;
+ }
+ break;
+ case LISTITEM_PERCENT_PLAYED:
+ value = std::to_string(GetPercentPlayed(tag));
+ return true;
+ case LISTITEM_VIDEO_CODEC:
+ value = tag->m_streamDetails.GetVideoCodec();
+ return true;
+ case LISTITEM_VIDEO_RESOLUTION:
+ value = CStreamDetails::VideoDimsToResolutionDescription(tag->m_streamDetails.GetVideoWidth(), tag->m_streamDetails.GetVideoHeight());
+ return true;
+ case LISTITEM_VIDEO_ASPECT:
+ value = CStreamDetails::VideoAspectToAspectDescription(tag->m_streamDetails.GetVideoAspect());
+ return true;
+ case LISTITEM_AUDIO_CODEC:
+ value = tag->m_streamDetails.GetAudioCodec();
+ return true;
+ case LISTITEM_AUDIO_CHANNELS:
+ {
+ int iChannels = tag->m_streamDetails.GetAudioChannels();
+ if (iChannels > 0)
+ {
+ value = std::to_string(iChannels);
+ return true;
+ }
+ break;
+ }
+ case LISTITEM_AUDIO_LANGUAGE:
+ value = tag->m_streamDetails.GetAudioLanguage();
+ return true;
+ case LISTITEM_SUBTITLE_LANGUAGE:
+ value = tag->m_streamDetails.GetSubtitleLanguage();
+ return true;
+ case LISTITEM_FILENAME:
+ case LISTITEM_FILE_EXTENSION:
+ if (item->IsVideoDb())
+ value = URIUtils::GetFileName(tag->m_strFileNameAndPath);
+ else if (item->HasMusicInfoTag()) // special handling for music videos, which have both a videotag and a musictag
+ break;
+ else
+ value = URIUtils::GetFileName(item->GetPath());
+
+ if (info.m_info == LISTITEM_FILE_EXTENSION)
+ {
+ std::string strExtension = URIUtils::GetExtension(value);
+ value = StringUtils::TrimLeft(strExtension, ".");
+ }
+ return true;
+ case LISTITEM_FOLDERNAME:
+ case LISTITEM_PATH:
+ if (item->IsVideoDb())
+ {
+ if (item->m_bIsFolder)
+ value = tag->m_strPath;
+ else
+ URIUtils::GetParentPath(tag->m_strFileNameAndPath, value);
+ }
+ else if (item->HasMusicInfoTag()) // special handling for music videos, which have both a videotag and a musictag
+ break;
+ else
+ URIUtils::GetParentPath(item->GetPath(), value);
+
+ value = CURL(value).GetWithoutUserDetails();
+
+ if (info.m_info == LISTITEM_FOLDERNAME)
+ {
+ URIUtils::RemoveSlashAtEnd(value);
+ value = URIUtils::GetFileName(value);
+ }
+ return true;
+ case LISTITEM_FILENAME_AND_PATH:
+ if (item->IsVideoDb())
+ value = tag->m_strFileNameAndPath;
+ else if (item->HasMusicInfoTag()) // special handling for music videos, which have both a videotag and a musictag
+ break;
+ else
+ value = item->GetPath();
+
+ value = CURL(value).GetWithoutUserDetails();
+ return true;
+ case LISTITEM_VIDEO_HDR_TYPE:
+ value = tag->m_streamDetails.GetVideoHdrType();
+ return true;
+ }
+ }
+
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // VIDEOPLAYER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case VIDEOPLAYER_PLAYLISTLEN:
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST::TYPE_VIDEO)
+ {
+ value = GUIINFO::GetPlaylistLabel(PLAYLIST_LENGTH);
+ return true;
+ }
+ break;
+ case VIDEOPLAYER_PLAYLISTPOS:
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST::TYPE_VIDEO)
+ {
+ value = GUIINFO::GetPlaylistLabel(PLAYLIST_POSITION);
+ return true;
+ }
+ break;
+ case VIDEOPLAYER_VIDEO_ASPECT:
+ value = CStreamDetails::VideoAspectToAspectDescription(CServiceBroker::GetDataCacheCore().GetVideoDAR());
+ return true;
+ case VIDEOPLAYER_STEREOSCOPIC_MODE:
+ value = CServiceBroker::GetDataCacheCore().GetVideoStereoMode();
+ return true;
+ case VIDEOPLAYER_SUBTITLES_LANG:
+ value = m_subtitleInfo.language;
+ return true;
+ break;
+ case VIDEOPLAYER_COVER:
+ if (m_appPlayer->IsPlayingVideo())
+ {
+ if (fallback)
+ *fallback = "DefaultVideoCover.png";
+
+ value = item->HasArt("thumb") ? item->GetArt("thumb") : "DefaultVideoCover.png";
+ return true;
+ }
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case LISTITEM_STEREOSCOPIC_MODE:
+ value = item->GetProperty("stereomode").asString();
+ if (value.empty() && tag)
+ value = CStereoscopicsManager::NormalizeStereoMode(tag->m_streamDetails.GetStereoMode());
+ return true;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // VIDEOPLAYER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case VIDEOPLAYER_VIDEO_CODEC:
+ value = m_videoInfo.codecName;
+ return true;
+ case VIDEOPLAYER_VIDEO_RESOLUTION:
+ value = CStreamDetails::VideoDimsToResolutionDescription(m_videoInfo.width, m_videoInfo.height);
+ return true;
+ case VIDEOPLAYER_HDR_TYPE:
+ value = CStreamDetails::HdrTypeToString(m_videoInfo.hdrType);
+ return true;
+ case VIDEOPLAYER_AUDIO_CODEC:
+ value = m_audioInfo.codecName;
+ return true;
+ case VIDEOPLAYER_AUDIO_CHANNELS:
+ {
+ int iChannels = m_audioInfo.channels;
+ if (iChannels > 0)
+ {
+ value = std::to_string(iChannels);
+ return true;
+ }
+ break;
+ }
+ case VIDEOPLAYER_AUDIO_BITRATE:
+ {
+ int iBitrate = m_audioInfo.bitrate;
+ if (iBitrate > 0)
+ {
+ value = std::to_string(std::lrint(static_cast<double>(iBitrate) / 1000.0));
+ return true;
+ }
+ break;
+ }
+ case VIDEOPLAYER_VIDEO_BITRATE:
+ {
+ int iBitrate = m_videoInfo.bitrate;
+ if (iBitrate > 0)
+ {
+ value = std::to_string(std::lrint(static_cast<double>(iBitrate) / 1000.0));
+ return true;
+ }
+ break;
+ }
+ case VIDEOPLAYER_AUDIO_LANG:
+ value = m_audioInfo.language;
+ return true;
+ }
+
+ return false;
+}
+
+bool CVideoGUIInfo::GetPlaylistInfo(std::string& value, const CGUIInfo& info) const
+{
+ const PLAYLIST::CPlayList& playlist =
+ CServiceBroker::GetPlaylistPlayer().GetPlaylist(PLAYLIST::TYPE_VIDEO);
+ if (playlist.size() < 1)
+ return false;
+
+ int index = info.GetData2();
+ if (info.GetData1() == 1)
+ { // relative index (requires current playlist is TYPE_VIDEO)
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() != PLAYLIST::TYPE_VIDEO)
+ return false;
+
+ index = CServiceBroker::GetPlaylistPlayer().GetNextSong(index);
+ }
+
+ if (index < 0 || index >= playlist.size())
+ return false;
+
+ const CFileItemPtr playlistItem = playlist[index];
+ // try to set a thumbnail
+ if (!playlistItem->HasArt("thumb"))
+ {
+ CVideoThumbLoader loader;
+ loader.LoadItem(playlistItem.get());
+ // still no thumb? then just the set the default cover
+ if (!playlistItem->HasArt("thumb"))
+ playlistItem->SetArt("thumb", "DefaultVideoCover.png");
+ }
+ if (info.m_info == VIDEOPLAYER_PLAYLISTPOS)
+ {
+ value = std::to_string(index + 1);
+ return true;
+ }
+ else if (info.m_info == VIDEOPLAYER_COVER)
+ {
+ value = playlistItem->GetArt("thumb");
+ return true;
+ }
+ else if (info.m_info == VIDEOPLAYER_ART)
+ {
+ value = playlistItem->GetArt(info.GetData3());
+ return true;
+ }
+
+ return GetLabel(value, playlistItem.get(), 0, CGUIInfo(info.m_info), nullptr);
+}
+
+bool CVideoGUIInfo::GetFallbackLabel(std::string& value,
+ const CFileItem* item,
+ int contextWindow,
+ const CGUIInfo& info,
+ std::string* fallback)
+{
+ // No fallback for videoplayer "offset" and "position" info labels
+ if (info.GetData1() && ((info.m_info >= VIDEOPLAYER_OFFSET_POSITION_FIRST &&
+ info.m_info <= VIDEOPLAYER_OFFSET_POSITION_LAST) ||
+ (info.m_info >= PLAYER_OFFSET_POSITION_FIRST && info.m_info <= PLAYER_OFFSET_POSITION_LAST)))
+ return false;
+
+ const CVideoInfoTag* tag = item->GetVideoInfoTag();
+ if (tag)
+ {
+ switch (info.m_info)
+ {
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // VIDEOPLAYER_*
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ case VIDEOPLAYER_TITLE:
+ value = item->GetLabel();
+ if (value.empty())
+ value = CUtil::GetTitleFromPath(item->GetPath());
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+bool CVideoGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ if (!gitem->IsFileItem())
+ return false;
+
+ const CFileItem *item = static_cast<const CFileItem*>(gitem);
+ const CVideoInfoTag* tag = item->GetVideoInfoTag();
+ if (tag)
+ {
+ switch (info.m_info)
+ {
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ case LISTITEM_PERCENT_PLAYED:
+ value = GetPercentPlayed(tag);
+ return true;
+ }
+ }
+
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // VIDEOPLAYER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case VIDEOPLAYER_AUDIOSTREAMCOUNT:
+ value = m_appPlayer->GetAudioStreamCount();
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool CVideoGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ if (!gitem->IsFileItem())
+ return false;
+
+ const CFileItem *item = static_cast<const CFileItem*>(gitem);
+ const CVideoInfoTag* tag = item->GetVideoInfoTag();
+ if (tag)
+ {
+ switch (info.m_info)
+ {
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // VIDEOPLAYER_*
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ case VIDEOPLAYER_HAS_INFO:
+ value = !tag->IsEmpty();
+ return true;
+
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ case LISTITEM_IS_RESUMABLE:
+ value = tag->GetResumePoint().timeInSeconds > 0;
+ return true;
+ case LISTITEM_IS_COLLECTION:
+ value = tag->m_type == MediaTypeVideoCollection;
+ return true;
+ }
+ }
+
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // VIDEOPLAYER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case VIDEOPLAYER_CONTENT:
+ {
+ std::string strContent = "files";
+ if (tag)
+ {
+ if (tag->m_type == MediaTypeMovie)
+ strContent = "movies";
+ else if (tag->m_type == MediaTypeEpisode)
+ strContent = "episodes";
+ else if (tag->m_type == MediaTypeMusicVideo)
+ strContent = "musicvideos";
+ }
+ value = StringUtils::EqualsNoCase(info.GetData3(), strContent);
+ return value; // if no match for this provider, other providers shall be asked.
+ }
+ case VIDEOPLAYER_USING_OVERLAYS:
+ value = (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_RENDERMETHOD) == RENDER_OVERLAYS);
+ return true;
+ case VIDEOPLAYER_ISFULLSCREEN:
+ value = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_VIDEO ||
+ CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_FULLSCREEN_GAME;
+ return true;
+ case VIDEOPLAYER_HASMENU:
+ value = m_appPlayer->GetSupportedMenuType() != MenuType::NONE;
+ return true;
+ case VIDEOPLAYER_HASTELETEXT:
+ value = m_appPlayer->HasTeletextCache();
+ return true;
+ case VIDEOPLAYER_HASSUBTITLES:
+ value = m_appPlayer->GetSubtitleCount() > 0;
+ return true;
+ case VIDEOPLAYER_SUBTITLESENABLED:
+ value = m_appPlayer->GetSubtitleVisible();
+ return true;
+ case VIDEOPLAYER_IS_STEREOSCOPIC:
+ value = !CServiceBroker::GetDataCacheCore().GetVideoStereoMode().empty();
+ return true;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // LISTITEM_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case LISTITEM_IS_STEREOSCOPIC:
+ {
+ std::string stereoMode = item->GetProperty("stereomode").asString();
+ if (stereoMode.empty() && tag)
+ stereoMode = CStereoscopicsManager::NormalizeStereoMode(tag->m_streamDetails.GetStereoMode());
+ if (!stereoMode.empty() && stereoMode != "mono")
+ value = true;
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/VideoGUIInfo.h b/xbmc/guilib/guiinfo/VideoGUIInfo.h
new file mode 100644
index 0000000..55202b2
--- /dev/null
+++ b/xbmc/guilib/guiinfo/VideoGUIInfo.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+
+#include <memory>
+
+class CApplicationPlayer;
+class CVideoInfoTag;
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CVideoGUIInfo : public CGUIInfoProvider
+{
+public:
+ CVideoGUIInfo();
+ ~CVideoGUIInfo() override = default;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetFallbackLabel(std::string& value,
+ const CFileItem* item,
+ int contextWindow,
+ const CGUIInfo& info,
+ std::string* fallback) override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+
+private:
+ int GetPercentPlayed(const CVideoInfoTag* tag) const;
+ bool GetPlaylistInfo(std::string& value, const CGUIInfo& info) const;
+
+ const std::shared_ptr<CApplicationPlayer> m_appPlayer;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/VisualisationGUIInfo.cpp b/xbmc/guilib/guiinfo/VisualisationGUIInfo.cpp
new file mode 100644
index 0000000..27a892f
--- /dev/null
+++ b/xbmc/guilib/guiinfo/VisualisationGUIInfo.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/VisualisationGUIInfo.h"
+
+#include "GUIUserMessages.h"
+#include "ServiceBroker.h"
+#include "addons/Addon.h"
+#include "addons/AddonManager.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIVisualisationControl.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/URIUtils.h"
+
+using namespace KODI::GUILIB::GUIINFO;
+
+bool CVisualisationGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ return false;
+}
+
+bool CVisualisationGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // VISUALISATION_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case VISUALISATION_PRESET:
+ {
+ CGUIMessage msg(GUI_MSG_GET_VISUALISATION, 0, 0);
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
+ if (msg.GetPointer())
+ {
+ CGUIVisualisationControl* viz = static_cast<CGUIVisualisationControl*>(msg.GetPointer());
+ if (viz)
+ {
+ value = viz->GetActivePresetName();
+ URIUtils::RemoveExtension(value);
+ return true;
+ }
+ }
+ break;
+ }
+ case VISUALISATION_NAME:
+ {
+ ADDON::AddonPtr addon;
+ value = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_MUSICPLAYER_VISUALISATION);
+ if (CServiceBroker::GetAddonMgr().GetAddon(value, addon, ADDON::OnlyEnabled::CHOICE_YES) &&
+ addon)
+ {
+ value = addon->Name();
+ return true;
+ }
+ break;
+ }
+ }
+
+ return false;
+}
+
+bool CVisualisationGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ return false;
+}
+
+bool CVisualisationGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // VISUALISATION_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case VISUALISATION_LOCKED:
+ {
+ CGUIMessage msg(GUI_MSG_GET_VISUALISATION, 0, 0);
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
+ if (msg.GetPointer())
+ {
+ CGUIVisualisationControl *pVis = static_cast<CGUIVisualisationControl*>(msg.GetPointer());
+ value = pVis->IsLocked();
+ return true;
+ }
+ break;
+ }
+ case VISUALISATION_ENABLED:
+ {
+ value = !CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_MUSICPLAYER_VISUALISATION).empty();
+ return true;
+ }
+ case VISUALISATION_HAS_PRESETS:
+ {
+ CGUIMessage msg(GUI_MSG_GET_VISUALISATION, 0, 0);
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
+ if (msg.GetPointer())
+ {
+ CGUIVisualisationControl* viz = static_cast<CGUIVisualisationControl*>(msg.GetPointer());
+ value = (viz && viz->HasPresets());
+ return true;
+ }
+ break;
+ }
+ }
+
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/VisualisationGUIInfo.h b/xbmc/guilib/guiinfo/VisualisationGUIInfo.h
new file mode 100644
index 0000000..d3cb05d
--- /dev/null
+++ b/xbmc/guilib/guiinfo/VisualisationGUIInfo.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CVisualisationGUIInfo : public CGUIInfoProvider
+{
+public:
+ CVisualisationGUIInfo() = default;
+ ~CVisualisationGUIInfo() override = default;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI
diff --git a/xbmc/guilib/guiinfo/WeatherGUIInfo.cpp b/xbmc/guilib/guiinfo/WeatherGUIInfo.cpp
new file mode 100644
index 0000000..3aa2044
--- /dev/null
+++ b/xbmc/guilib/guiinfo/WeatherGUIInfo.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "guilib/guiinfo/WeatherGUIInfo.h"
+
+#include "FileItem.h"
+#include "LangInfo.h"
+#include "ServiceBroker.h"
+#include "guilib/guiinfo/GUIInfo.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+#include "weather/WeatherManager.h"
+
+using namespace KODI::GUILIB::GUIINFO;
+
+bool CWeatherGUIInfo::InitCurrentItem(CFileItem *item)
+{
+ return false;
+}
+
+bool CWeatherGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // WEATHER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case WEATHER_CONDITIONS_TEXT:
+ value = CServiceBroker::GetWeatherManager().GetInfo(WEATHER_LABEL_CURRENT_COND);
+ StringUtils::Trim(value);
+ return true;
+ case WEATHER_CONDITIONS_ICON:
+ value = CServiceBroker::GetWeatherManager().GetInfo(WEATHER_IMAGE_CURRENT_ICON);
+ return true;
+ case WEATHER_TEMPERATURE:
+ value = StringUtils::Format(
+ "{}{}", CServiceBroker::GetWeatherManager().GetInfo(WEATHER_LABEL_CURRENT_TEMP),
+ g_langInfo.GetTemperatureUnitString());
+ return true;
+ case WEATHER_LOCATION:
+ value = CServiceBroker::GetWeatherManager().GetInfo(WEATHER_LABEL_LOCATION);
+ return true;
+ case WEATHER_FANART_CODE:
+ value = URIUtils::GetFileName(CServiceBroker::GetWeatherManager().GetInfo(WEATHER_IMAGE_CURRENT_ICON));
+ URIUtils::RemoveExtension(value);
+ return true;
+ case WEATHER_PLUGIN:
+ value = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_WEATHER_ADDON);
+ return true;
+ }
+
+ return false;
+}
+
+bool CWeatherGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ return false;
+}
+
+bool CWeatherGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
+{
+ switch (info.m_info)
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // WEATHER_*
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ case WEATHER_IS_FETCHED:
+ value = CServiceBroker::GetWeatherManager().IsFetched();
+ return true;;
+ }
+
+ return false;
+}
diff --git a/xbmc/guilib/guiinfo/WeatherGUIInfo.h b/xbmc/guilib/guiinfo/WeatherGUIInfo.h
new file mode 100644
index 0000000..560d025
--- /dev/null
+++ b/xbmc/guilib/guiinfo/WeatherGUIInfo.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "guilib/guiinfo/GUIInfoProvider.h"
+
+namespace KODI
+{
+namespace GUILIB
+{
+namespace GUIINFO
+{
+
+class CGUIInfo;
+
+class CWeatherGUIInfo : public CGUIInfoProvider
+{
+public:
+ CWeatherGUIInfo() = default;
+ ~CWeatherGUIInfo() override = default;
+
+ // KODI::GUILIB::GUIINFO::IGUIInfoProvider implementation
+ bool InitCurrentItem(CFileItem *item) override;
+ bool GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const override;
+ bool GetInt(int& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+ bool GetBool(bool& value, const CGUIListItem *item, int contextWindow, const CGUIInfo &info) const override;
+};
+
+} // namespace GUIINFO
+} // namespace GUILIB
+} // namespace KODI