/*
 *  Copyright (C) 2005-2026 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 "GUIInfoManager.h"

#include "FileItem.h"
#include "ServiceBroker.h"
#include "URL.h"
#include "Util.h"
#include "application/ApplicationComponents.h"
#include "application/ApplicationPlayer.h"
#include "cores/DataCacheCore.h"
#include "filesystem/File.h"
#include "games/tags/GameInfoTag.h"
#include "guilib/guiinfo/GUIInfo.h"
#include "guilib/guiinfo/GUIInfoHelper.h"
#include "guilib/guiinfo/GUIInfoLabels.h"
#include "input/WindowTranslator.h"
#include "interfaces/AnnouncementManager.h"
#include "interfaces/info/InfoExpression.h"
#include "messaging/ApplicationMessenger.h"
#include "playlists/PlayListTypes.h"
#include "settings/SkinSettings.h"
#include "utils/ArtUtils.h"
#include "utils/CharsetConverter.h"
#include "utils/FileUtils.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
#include "utils/log.h"
#include "windowing/WinSystem.h"

#include <algorithm>
#include <array>
#include <charconv>
#include <cmath>
#include <functional>
#include <iterator>
#include <memory>
#include <mutex>

using namespace KODI;
using namespace KODI::GUILIB;
using namespace KODI::GUILIB::GUIINFO;
using namespace INFO;

namespace
{
struct InfoMap
{
  std::string_view str{};
  int val{0};
};

/// \page modules__infolabels_boolean_conditions Infolabels and Boolean conditions
/// \tableofcontents
///
/// \section modules__infolabels_boolean_conditions_Description Description
/// Skins can use boolean conditions with the <b>\<visible\></b> tag or with condition
/// attributes. Scripts can read boolean conditions with
/// <b>xbmc.getCondVisibility(condition)</b>.
///
/// Skins can use infolabels with <b>$INFO[infolabel]</b> or the <b>\<info\></b> tag. Scripts
/// can read infolabels with <b>xbmc.getInfoLabel('infolabel')</b>.
///
/// @todo [docs] Improve the description and create links for functions
/// @todo [docs] Separate boolean conditions from infolabels
/// @todo [docs] Order items alphabetically within subsections for a better search experience
/// @todo [docs] Order subsections alphabetically
/// @todo [docs] Use links instead of bold values for infolabels/bools
/// so we can use a link to point users when providing help
///

/// \page modules__infolabels_boolean_conditions
/// \section modules_list_infolabels_booleans List of Infolabels and Boolean conditions
/// \subsection modules__infolabels_boolean_conditions_GlobalBools Global
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`true`</b>,
///                  \anchor Global_True
///                  _boolean_,
///     @return Always evaluates to **true**.
///     <p>
///   }
///   \table_row3{   <b>`false`</b>,
///                  \anchor Global_False
///                  _boolean_,
///     @return Always evaluates to **false**.
///     <p>
///   }
///   \table_row3{   <b>`yes`</b>,
///                  \anchor Global_Yes
///                  _boolean_,
///     @return same as \link Global_True `true` \endlink.
///     <p>
///   }
///   \table_row3{   <b>`no`</b>,
///                  \anchor Global_No
///                  _boolean_,
///     @return same as \link Global_False `false` \endlink.
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Addon Addon
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Addon.SettingStr(addon_id\,setting_id)`</b>,
///                  \anchor Addon_SettingString
///                  _string_,
///     @return The string value of the setting `setting_id` belonging to the addon with the id `addon_id`.
///     @param addon_id - the id of the addon
///     @param setting_id - the addon setting
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link Addon_SettingString `Addon.SettingStr(addon_id\,setting_id)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Addon.SettingBool(addon_id\,setting_id)`</b>,
///                  \anchor Addon_SettingBool
///                  _boolean_,
///     @return **True** if the setting `setting_id` belonging to the addon with the id `addon_id` is **True**\, **False** otherwise.
///     @note The provided setting with `setting_id` must be a boolean setting type. Otherwise it will return the boolean info
///     default value (which is **False**).
///     @param addon_id - the id of the addon
///     @param setting_id - the addon setting
///     <p><hr>
///     @skinning_v20 **[New Boolean Condition]** \link Addon_SettingBool `Addon.SettingBool(addon_id\,setting_id)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Addon.SettingInt(addon_id\,setting_id)`</b>,
///                  \anchor Addon_SettingInt
///                  _integer_,
///     @return The integer value of the setting `setting_id` belong to the addon with the id `addon_id`.
///     @note The provided setting with `setting_id` must be an integer setting type. Otherwise it will return the integer info
///     default value (which is 0).
///     @param addon_id - the id of the addon
///     @param setting_id - the addon setting
///     <p><hr>
///     @skinning_v20 **[New Integer Info]** \link Addon_SettingInt `Addon.SettingInt(addon_id\,setting_id)`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 3> addons = {{
    {"settingstr",  ADDON_SETTING_STRING},
    {"settingbool", ADDON_SETTING_BOOL},
    {"settingint",  ADDON_SETTING_INT},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_String String
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`String.IsEmpty(info)`</b>,
///                  \anchor String_IsEmpty
///                  _boolean_,
///     @return **True** if the info is empty.
///     @param info - infolabel
///     @note **Example of info:** \link ListItem_Title `ListItem.Title` \endlink \,
///     \link ListItem_Genre `ListItem.Genre` \endlink.
///     Please note that string can also be a `$LOCALIZE[]`.
///     Also note that in a panelview or similar this only works on the focused item
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link String_IsEmpty `String.IsEmpty(info)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`String.IsEqual(info\,string)`</b>,
///                  \anchor String_IsEqual
///                  _boolean_,
///     @return **True** if the info is equal to the given string.
///     @param info - infolabel
///     @param string - comparison string
///     @note **Example of info:** \link ListItem_Title `ListItem.Title` \endlink \,
///     \link ListItem_Genre `ListItem.Genre` \endlink.
///     Please note that string can also be a `$LOCALIZE[]`.
///     Also note that in a panelview or similar this only works on the focused item
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link String_IsEqual `String.IsEqual(info\,string)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`String.StartsWith(info\,substring)`</b>,
///                  \anchor String_StartsWith
///                  _boolean_,
///     @return **True** if the info starts with the given substring.
///     @param info - infolabel
///     @param substring - substring to check
///     @note **Example of info:** \link ListItem_Title `ListItem.Title` \endlink \,
///     \link ListItem_Genre `ListItem.Genre` \endlink.
///     Please note that string can also be a `$LOCALIZE[]`.
///     Also note that in a panelview or similar this only works on the focused item
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link String_StartsWith `String.StartsWith(info\,substring)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`String.EndsWith(info\,substring)`</b>,
///                  \anchor String_EndsWith
///                  _boolean_,
///     @return **True** if the info ends with the given substring.
///     @param info - infolabel
///     @param substring - substring to check
///     @note **Example of info:** \link ListItem_Title `ListItem.Title` \endlink \,
///     \link ListItem_Genre `ListItem.Genre` \endlink.
///     Please note that string can also be a `$LOCALIZE[]`.
///     Also note that in a panelview or similar this only works on the focused item
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link String_EndsWith `String.EndsWith(info\,substring)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`String.Contains(info\,substring)`</b>,
///                  \anchor String_Contains
///                  _boolean_,
///     @return **True** if the info contains the given substring.
///     @param info - infolabel
///     @param substring - substring to check
///     @note **Example of info:** \link ListItem_Title `ListItem.Title` \endlink \,
///     \link ListItem_Genre `ListItem.Genre` \endlink.
///     Please note that string can also be a `$LOCALIZE[]`.
///     Also note that in a panelview or similar this only works on the focused item
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link String_Contains `String.Contains(info\,substring)`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 5> string_bools = {{
    {"isempty",     STRING_IS_EMPTY},
    {"isequal",     STRING_IS_EQUAL},
    {"startswith",  STRING_STARTS_WITH},
    {"endswith",    STRING_ENDS_WITH},
    {"contains",    STRING_CONTAINS},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Integer Integer
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Integer.ValueOf(number)`</b>,
///                  \anchor Integer_ValueOf
///                  _integer_,
///     @return An integer info label that represents the provided number
///     @param number - the number to compute
///     @note **Example:** `Integer.ValueOf(4)` will be evaluated to 4.
///     @note Will return -1 if not able to convert the provided value to an integer. **Example**: `Integer.ValueOf(some string)` will evaluate to -1
///     as the provided argument is not an integer.
///     <p><hr>
///     @skinning_v20 **[New InfoLabel]** \link Integer_ValueOf `Integer.ValueOf(number)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Integer.IsEqual(info\,number)`</b>,
///                  \anchor Integer_IsEqual
///                  _boolean_,
///     @return **True** if the value of the infolabel is equal to the supplied number.
///     @param info - infolabel
///     @param number - number or integer infolabel to compare
///     @note **Example:** `Integer.IsEqual(ListItem.Year\,2000)`
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Integer_IsEqual `Integer.IsEqual(info\,number)`\endlink
///     @skinning_v20 \link Integer_IsEqual `Integer.IsEqual(info\,number)`\endlink now supports comparisons against other integer infos
///     and not just fixed number values.
///     <p>
///   }
///   \table_row3{   <b>`Integer.IsGreater(info\,number)`</b>,
///                  \anchor Integer_IsGreater
///                  _boolean_,
///     @return **True** if the value of the infolabel is greater than to the supplied number.
///     @param info - infolabel
///     @param number - number or integer infolabel to compare
///     @note **Example:** `Integer.IsGreater(ListItem.Year\,2000)`
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Integer_IsGreater `Integer.IsGreater(info\,number)`\endlink
///     @skinning_v20 \link Integer_IsGreater `Integer.IsGreater(info\,number)`\endlink now supports comparisons against other integer infos
///     and not just fixed number values.
///     <p>
///   }
///   \table_row3{   <b>`Integer.IsGreaterOrEqual(info\,number)`</b>,
///                  \anchor Integer_IsGreaterOrEqual
///                  _boolean_,
///     @return **True** if the value of the infolabel is greater or equal to the supplied number.
///     @param info - infolabel
///     @param number - number or integer infolabel to compare
///     @note **Example:** `Integer.IsGreaterOrEqual(ListItem.Year\,2000)`
///     @note **Example2:** `Integer.IsGreaterOrEqual(Container(x).ListItem(1).Year\,Container(x).ListItem(2).Year)`
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Integer_IsGreaterOrEqual `Integer.IsGreaterOrEqual(info\,number)`\endlink
///     @skinning_v20 \link Integer_IsGreaterOrEqual `Integer.IsGreaterOrEqual(info\,number)`\endlink now supports comparisons against other integer infos
///     and not just fixed number values.
///     <p>
///   }
///   \table_row3{   <b>`Integer.IsLess(info\,number)`</b>,
///                  \anchor Integer_IsLess
///                  _boolean_,
///     @return **True** if the value of the infolabel is less than the supplied number.
///     @param info - infolabel
///     @param number - number or integer infolabel to compare
///     @note **Example:** `Integer.IsLess(ListItem.Year\,2000)`
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Integer_IsLess `Integer.IsLess(info\,number)`\endlink
///     @skinning_v20 \link Integer_IsLess `Integer.IsLess(info\,number)`\endlink now supports comparisons against other integer infos
///     and not just fixed number values.
///     <p>
///   }
///   \table_row3{   <b>`Integer.IsLessOrEqual(info\,number)`</b>,
///                  \anchor Integer_IsLessOrEqual
///                  _boolean_,
///     @return **True** if the value of the infolabel is less or equal to the supplied number.
///     @param info - infolabel
///     @param number - number or integer infolabel to compare
///     @note **Example:** `Integer.IsLessOrEqual(ListItem.Year\,2000)`
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Integer_IsLessOrEqual `Integer.IsLessOrEqual(info\,number)`\endlink
///     @skinning_v20 \link Integer_IsLessOrEqual `Integer.IsLessOrEqual(info\,number)`\endlink now supports comparisons against other integer infos
///     and not just fixed number values.
///     <p>
///   }
///   \table_row3{   <b>`Integer.IsEven(info)`</b>,
///                  \anchor Integer_IsEven
///                  _boolean_,
///     @return **True** if the value of the infolabel is odd
///     @param info - infolabel
///     @note **Example:** `Integer.IsEven(ListItem.CurrentItem)`
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link Integer_IsEven `Integer.IsEven(info)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Integer.IsOdd(info)`</b>,
///                  \anchor Integer_IsOdd
///                  _boolean_,
///     @return **True** if the value of the infolabel is odd
///     @param info - infolabel
///     @note **Example:** `Integer.IsOdd(ListItem.CurrentItem)`
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link Integer_IsOdd `Integer.IsOdd(info)`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 7> integer_bools = {{
    {"isequal",           INTEGER_IS_EQUAL},
    {"isgreater",         INTEGER_GREATER_THAN},
    {"isgreaterorequal",  INTEGER_GREATER_OR_EQUAL},
    {"isless",            INTEGER_LESS_THAN},
    {"islessorequal",     INTEGER_LESS_OR_EQUAL},
    {"iseven",            INTEGER_EVEN},
    {"isodd",             INTEGER_ODD},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Player Player
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Player.HasAudio`</b>,
///                  \anchor Player_HasAudio
///                  _boolean_,
///     @return **True** if the player has an audio file.
///     <p>
///   }
///   \table_row3{   <b>`Player.HasGame`</b>,
///                  \anchor Player_HasGame
///                  _boolean_,
///     @return **True** if the player has a game file (RETROPLAYER).
///     <p><hr>
///     @skinning_v18 **[New Boolean Condition]** \link Player_HasGame `Player.HasGame`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.HasMedia`</b>,
///                  \anchor Player_HasMedia
///                  _boolean_,
///     @return **True** if the player has an audio or video file.
///     <p>
///   }
///   \table_row3{   <b>`Player.HasVideo`</b>,
///                  \anchor Player_HasVideo
///                  _boolean_,
///     @return **True** if the player has a video file.
///     <p>
///   }
///   \table_row3{   <b>`Player.Paused`</b>,
///                  \anchor Player_Paused
///                  _boolean_,
///     @return **True** if the player is paused.
///     <p>
///   }
///   \table_row3{   <b>`Player.Playing`</b>,
///                  \anchor Player_Playing
///                  _boolean_,
///     @return **True** if the player is currently playing (i.e. not ffwding\,
///     rewinding or paused.)
///     <p>
///   }
///   \table_row3{   <b>`Player.Rewinding`</b>,
///                  \anchor Player_Rewinding
///                  _boolean_,
///     @return **True** if the player is rewinding.
///     <p>
///   }
///   \table_row3{   <b>`Player.Rewinding2x`</b>,
///                  \anchor Player_Rewinding2x
///                  _boolean_,
///     @return **True** if the player is rewinding at 2x.
///     <p>
///   }
///   \table_row3{   <b>`Player.Rewinding4x`</b>,
///                  \anchor Player_Rewinding4x
///                  _boolean_,
///     @return **True** if the player is rewinding at 4x.
///     <p>
///   }
///   \table_row3{   <b>`Player.Rewinding8x`</b>,
///                  \anchor Player_Rewinding8x
///                  _boolean_,
///     @return **True** if the player is rewinding at 8x.
///     <p>
///   }
///   \table_row3{   <b>`Player.Rewinding16x`</b>,
///                  \anchor Player_Rewinding16x
///                  _boolean_,
///     @return **True** if the player is rewinding at 16x.
///     <p>
///   }
///   \table_row3{   <b>`Player.Rewinding32x`</b>,
///                  \anchor Player_Rewinding32x
///                  _boolean_,
///     @return **True** if the player is rewinding at 32x.
///     <p>
///   }
///   \table_row3{   <b>`Player.Forwarding`</b>,
///                  \anchor Player_Forwarding
///                  _boolean_,
///     @return **True** if the player is fast forwarding.
///     <p>
///   }
///   \table_row3{   <b>`Player.Forwarding2x`</b>,
///                  \anchor Player_Forwarding2x
///                  _boolean_,
///     @return **True** if the player is fast forwarding at 2x.
///     <p>
///   }
///   \table_row3{   <b>`Player.Forwarding4x`</b>,
///                  \anchor Player_Forwarding4x
///                  _boolean_,
///     @return **True** if the player is fast forwarding at 4x.
///     <p>
///   }
///   \table_row3{   <b>`Player.Forwarding8x`</b>,
///                  \anchor Player_Forwarding8x
///                  _boolean_,
///     @return **True** if the player is fast forwarding at 8x.
///     <p>
///   }
///   \table_row3{   <b>`Player.Forwarding16x`</b>,
///                  \anchor Player_Forwarding16x
///                  _boolean_,
///     @return **True** if the player is fast forwarding at 16x.
///     <p>
///   }
///   \table_row3{   <b>`Player.Forwarding32x`</b>,
///                  \anchor Player_Forwarding32x
///                  _boolean_,
///     @return **True** if the player is fast forwarding at 32x.
///     <p>
///   }
///   \table_row3{   <b>`Player.Caching`</b>,
///                  \anchor Player_Caching
///                  _boolean_,
///     @return **True** if the player is current re-caching data (internet based
///     video playback).
///     <p>
///   }
///   \table_row3{   <b>`Player.DisplayAfterSeek`</b>,
///                  \anchor Player_DisplayAfterSeek
///                  _boolean_,
///     @return **True** for the first 2.5 seconds after a seek.
///     <p>
///   }
///   \table_row3{   <b>`Player.Seekbar`</b>,
///                  \anchor Player_Seekbar
///                  _integer_,
///     @return The percentage of one seek to other position.
///     <p>
///   }
///   \table_row3{   <b>`Player.Seeking`</b>,
///                  \anchor Player_Seeking
///                  _boolean_,
///     @return **True** if a seek is in progress.
///     <p>
///   }
///   \table_row3{   <b>`Player.ShowTime`</b>,
///                  \anchor Player_ShowTime
///                  _boolean_,
///     @return **True** if the user has requested the time to show (occurs in video
///     fullscreen).
///     <p>
///   }
///   \table_row3{   <b>`Player.ShowInfo`</b>,
///                  \anchor Player_ShowInfo
///                  _boolean_,
///     @return **True** if the user has requested the song info to show (occurs in
///     visualisation fullscreen and slideshow).
///     <p>
///   }
///   \table_row3{   <b>`Player.Title`</b>,
///                  \anchor Player_Title
///                  _string_,
///     @return The Musicplayer title for audio and the Videoplayer title for
///     video.
///     <p>
///   }
///   \table_row3{   <b>`Player.offset(number).Title`</b>,
///                  \anchor Player_Offset_Title
///                  _string_,
///     @return The title of audio or video which has an offset `number` with respect to the currently playing item.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link Player_Offset_Title `Player.offset(number).Title`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.position(number).Title`</b>,
///                  \anchor Player_Position_Title
///                  _string_,
///     @return The title of the audio or video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link Player_Position_Title `Player.position(number).Title`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Muted`</b>,
///                  \anchor Player_Muted
///                  _boolean_,
///     @return **True** if the volume is muted.
///     <p>
///   }
///   \table_row3{   <b>`Player.HasDuration`</b>,
///                  \anchor Player_HasDuration
///                  _boolean_,
///     @return **True** if Media is not a true stream.
///     <p>
///   }
///   \table_row3{   <b>`Player.Passthrough`</b>,
///                  \anchor Player_Passthrough
///                  _boolean_,
///     @return **True** if the player is using audio passthrough.
///     <p>
///   }
///   \table_row3{   <b>`Player.CacheLevel`</b>,
///                  \anchor Player_CacheLevel
///                  _string_,
///     @return The used cache level as a string with an integer number.
///     <p>
///   }
///   \table_row3{   <b>`Player.Progress`</b>,
///                  \anchor Player_Progress
///                  _integer_ / _string_,
///     @return The progress position as percentage.
///     <p><hr>
///     @skinning_v19 \link Player_Progress `Player.Progress`\endlink infolabel
///     also exposed as a string.
///     <p>
///   }
///   \table_row3{   <b>`Player.ProgressCache`</b>,
///                  \anchor Player_ProgressCache
///                  _integer_ / _string_,
///     @return How much of the file is cached above current play percentage
///     <p><hr>
///     @skinning_v19 \link Player_ProgressCache `Player.ProgressCache`\endlink
///     infolabel also exposed as a string.
///     <p>
///   }
///   \table_row3{   <b>`Player.Volume`</b>,
///                  \anchor Player_Volume
///                  _string_,
///     @return The current player volume with the format `%2.1f` dB
///     <p>
///   }
///   \table_row3{   <b>`Player.SubtitleDelay`</b>,
///                  \anchor Player_SubtitleDelay
///                  _string_,
///     @return The used subtitle delay with the format `%2.3f` s
///     <p>
///   }
///   \table_row3{   <b>`Player.AudioDelay`</b>,
///                  \anchor Player_AudioDelay
///                  _string_,
///     @return The used audio delay with the format `%2.3f` s
///     <p>
///   }
///   \table_row3{   <b>`Player.Chapter`</b>,
///                  \anchor Player_Chapter
///                  _integer_,
///     @return The current chapter of current playing media.
///     <p>
///   }
///   \table_row3{   <b>`Player.ChapterCount`</b>,
///                  \anchor Player_ChapterCount
///                  _integer_,
///     @return The total number of chapters of current playing media.
///     <p>
///   }
///   \table_row3{   <b>`Player.ChapterName`</b>,
///                  \anchor Player_ChapterName
///                  _string_,
///     @return The name of currently used chapter if available.
///     <p>
///   }
///   \table_row3{   <b>`Player.Folderpath`</b>,
///                  \anchor Player_Folderpath
///                  _string_,
///     @return The full path of the currently playing song or movie
///     <p>
///   }
///   \table_row3{   <b>`Player.offset(number).Folderpath`</b>,
///                  \anchor Player_Offset_Folderpath
///                  _string_,
///     @return The full path of the audio or video file which has an offset `number` with respect to the currently playing item.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link Player_Offset_Folderpath `Player.offset(number).Folderpath`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.position(number).Folderpath`</b>,
///                  \anchor Player_Position_Folderpath
///                  _string_,
///     @return The full path of the audio or video file which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link Player_Position_Folderpath `Player.position(number).Folderpath`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.FilenameAndPath`</b>,
///                  \anchor Player_FilenameAndPath
///                  _string_,
///     @return The full path with filename of the currently
///     playing song or movie
///     <p>
///   }
///   \table_row3{   <b>`Player.offset(number).FilenameAndPath`</b>,
///                  \anchor Player_Offset_FilenameAndPath
///                  _string_,
///     @return The full path with filename of audio or video file which has an offset `number` with respect to the currently playing item.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link Player_Offset_FilenameAndPath `Player.offset(number).FilenameAndPath`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.position(number).FilenameAndPath`</b>,
///                  \anchor Player_Position_FilenameAndPath
///                  _string_,
///     @return The full path with filename of the audio or video file which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link Player_Position_FilenameAndPath `Player.position(number).FilenameAndPath`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Filename`</b>,
///                  \anchor Player_Filename
///                  _string_,
///     @return The filename of the currently playing media.
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Player_Filename `Player.Filename`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.offset(number).Filename`</b>,
///                  \anchor Player_Offset_Filename
///                  _string_,
///     @return The filename of audio or video file which has an offset `number` with respect to the currently playing item.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link Player_Offset_Filename `Player.offset(number).Filename`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.position(number).Filename`</b>,
///                  \anchor Player_Position_Filename
///                  _string_,
///     @return The filename of the audio or video file which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link Player_Position_Filename `Player.position(number).Filename`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.IsInternetStream`</b>,
///                  \anchor Player_IsInternetStream
///                  _boolean_,
///     @return **True** if the player is playing an internet stream.
///     <p>
///   }
///   \table_row3{   <b>`Player.PauseEnabled`</b>,
///                  \anchor Player_PauseEnabled
///                  _boolean_,
///     @return **True** if played stream is paused.
///     <p>
///   }
///   \table_row3{   <b>`Player.SeekEnabled`</b>,
///                  \anchor Player_SeekEnabled
///                  _boolean_,
///     @return **True** if seek on playing is enabled.
///     <p>
///   }
///   \table_row3{   <b>`Player.ChannelPreviewActive`</b>,
///                  \anchor Player_ChannelPreviewActive
///                  _boolean_,
///     @return **True** if PVR channel preview is active (used
///     channel tag different from played tag)
///     <p>
///   }
///   \table_row3{   <b>`Player.TempoEnabled`</b>,
///                  \anchor Player_TempoEnabled
///                  _boolean_,
///     @return **True** if player supports tempo (i.e. speed up/down normal
///     playback speed)
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Player_TempoEnabled `Player.TempoEnabled`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.IsTempo`</b>,
///                  \anchor Player_IsTempo
///                  _boolean_,
///     @return **True** if player has tempo (i.e. is playing with a playback speed higher or
///     lower than normal playback speed)
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Player_IsTempo `Player.IsTempo`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.PlaySpeed`</b>,
///                  \anchor Player_PlaySpeed
///                  _string_,
///     @return The player playback speed with the format `%1.2f` (1.00 means normal
///     playback speed).
///     @note For Tempo\, the default range is 0.80 - 1.50 (it can be changed
///     in advanced settings). If \ref Player_PlaySpeed "Player.PlaySpeed" returns a value different from 1.00
///     and \ref Player_IsTempo "Player.IsTempo" is false it means the player is in ff/rw mode.
///     <p>
///   }
///   \table_row3{   <b>`Player.HasResolutions`</b>,
///                  \anchor Player_HasResolutions
///                  _boolean_,
///     @return **True** if the player is allowed to switch resolution and refresh rate
///     (i.e. if whitelist modes are configured in Kodi's System/Display settings)
///     <p><hr>
///     @skinning_v18 **[New Boolean Condition]** \link Player_HasResolutions `Player.HasResolutions`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.HasPrograms`</b>,
///                  \anchor Player_HasPrograms
///                  _boolean_,
///     @return **True** if the media file being played has programs\, i.e. groups of streams.
///     @note Ex: if a media file has multiple streams (quality\, channels\, etc) a program represents
///     a particular stream combo.
///     <p>
///   }
///   \table_row3{   <b>`Player.FrameAdvance`</b>,
///                  \anchor Player_FrameAdvance
///                  _boolean_,
///     @return **True** if player is in frame advance mode.
///     @note Skins should hide seek bar in this mode
///     <p><hr>
///     @skinning_v18 **[New Boolean Condition]** \link Player_FrameAdvance `Player.FrameAdvance`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Icon`</b>,
///                  \anchor Player_Icon
///                  _string_,
///     @return The thumbnail of the currently playing item. If no thumbnail image exists\,
///     the icon will be returned\, if available.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link Player_Icon `Player.Icon`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Editlist`</b>,
///                  \anchor Player_Editlist
///                  _string_,
///     @return The editlist of the currently playing item as csv in the format start1\,end1\,start2\,end2\,...
///     Tokens have values in the range from 0.0 to 100.0. end token is greater or equal to the  start token.
///     @note This infolabel does not contain EDL cuts. Edits start and end times are adjusted according to cuts
///     defined for the media item.
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link Player_Editlist `Player.Editlist`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Cuts`</b>,
///                  \anchor Player_Cuts
///                  _string_,
///     @return The EDL cut markers of the currently playing item as csv in the format start1\,end1\,start2\,end2\,...
///     Tokens have values in the range from 0.0 to 100.0. end token is greater or equal to the  start token.
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link Player_Cuts `Player.Cuts`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.SceneMarkers`</b>,
///                  \anchor Player_SceneMarkers
///                  _string_,
///     @return The EDL scene markers of the currently playing item as csv in the format start1\,end1\,start2\,end2\,...
///     Tokens have values in the range from 0.0 to 100.0. end token is greater or equal to the  start token.
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link Player_SceneMarkers `Player.SceneMarkers`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.HasSceneMarkers`</b>,
///                  \anchor Player_HasSceneMarkers
///                  _boolean_,
///     @return **True** if the item being played has scene markers\, **False** otherwise
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link Player_HasSceneMarkers `Player.HasSceneMarkers`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Chapters`</b>,
///                  \anchor Player_Chapters
///                  _string_,
///     @return The chapters of the currently playing item as csv in the format start1\,end1\,start2\,end2\,...
///     Tokens have values in the range from 0.0 to 100.0. end token is greater or equal to the  start token.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link Player_Chapters `Player.Chapters`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Bookmarks`</b>,
///                  \anchor Player_Bookmarks
///                  _string_,
///     @return The bookmarks of the currently playing item as csv in the format start1\,end1\,start2\,end2\,...
///     Tokens have values in the range from 0.0 to 100.0. end token is greater or equal to the  start token.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Player_Bookmarks `Player.Bookmarks`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.HasBookmarks`</b>,
///                  \anchor Player_HasBookmarks
///                  _boolean_,
///     @return **True** if the item being played has bookmarks\, **False** otherwise
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Player_HasBookmarks `Player.HasBookmarks`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.IsExternal`</b>,
///                  \anchor Player_IsExternal
///                  _boolean_,
///     @return **True** if the playing player is an external player\, **False** otherwise
///     <p><hr>
///     @skinning_v21 **[New Boolean Condition]** \link Player_IsExternal `Player.IsExternal`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.IsRemote`</b>,
///                  \anchor Player_IsRemote
///                  _boolean_,
///     @return **True** if the playing player is a remote player (e.g. UPnP)\, **False** otherwise
///     <p><hr>
///     @skinning_v21 **[New Boolean Condition]** \link Player_IsRemote `Player.IsRemote`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.IsLive`</b>,
///                  \anchor Player_IsLive
///                  _boolean_,
///     @return **True** if the inputstream of the player is a live stream (a.k.a. real time stream)\, **False** otherwise
///     <p><hr>
///     @skinning_v22 **[New Boolean Condition]** \link Player_IsLive `Player.IsLive`\endlink
///     <p>
///   }
// clang-format off
constexpr std::array<InfoMap, 60> player_labels = {{
    {"hasmedia",              PLAYER_HAS_MEDIA},
    {"hasaudio",              PLAYER_HAS_AUDIO},
    {"hasvideo",              PLAYER_HAS_VIDEO},
    {"hasgame",               PLAYER_HAS_GAME},
    {"isexternal",            PLAYER_IS_EXTERNAL},
    {"isremote",              PLAYER_IS_REMOTE},
    {"islive",                PLAYER_IS_LIVE},
    {"playing",               PLAYER_PLAYING},
    {"paused",                PLAYER_PAUSED},
    {"rewinding",             PLAYER_REWINDING},
    {"forwarding",            PLAYER_FORWARDING},
    {"rewinding2x",           PLAYER_REWINDING_2x},
    {"rewinding4x",           PLAYER_REWINDING_4x},
    {"rewinding8x",           PLAYER_REWINDING_8x},
    {"rewinding16x",          PLAYER_REWINDING_16x},
    {"rewinding32x",          PLAYER_REWINDING_32x},
    {"forwarding2x",          PLAYER_FORWARDING_2x},
    {"forwarding4x",          PLAYER_FORWARDING_4x},
    {"forwarding8x",          PLAYER_FORWARDING_8x},
    {"forwarding16x",         PLAYER_FORWARDING_16x},
    {"forwarding32x",         PLAYER_FORWARDING_32x},
    {"caching",               PLAYER_CACHING},
    {"seekbar",               PLAYER_SEEKBAR},
    {"seeking",               PLAYER_SEEKING},
    {"showtime",              PLAYER_SHOWTIME},
    {"showinfo",              PLAYER_SHOWINFO},
    {"muted",                 PLAYER_MUTED},
    {"hasduration",           PLAYER_HASDURATION},
    {"passthrough",           PLAYER_PASSTHROUGH},
    {"cachelevel",            PLAYER_CACHELEVEL},
    {"title",                 PLAYER_TITLE},
    {"progress",              PLAYER_PROGRESS},
    {"progresscache",         PLAYER_PROGRESS_CACHE},
    {"volume",                PLAYER_VOLUME},
    {"subtitledelay",         PLAYER_SUBTITLE_DELAY},
    {"audiodelay",            PLAYER_AUDIO_DELAY},
    {"chapter",               PLAYER_CHAPTER},
    {"chaptercount",          PLAYER_CHAPTERCOUNT},
    {"chaptername",           PLAYER_CHAPTERNAME},
    {"folderpath",            PLAYER_PATH},
    {"filenameandpath",       PLAYER_FILEPATH},
    {"filename",              PLAYER_FILENAME},
    {"isinternetstream",      PLAYER_ISINTERNETSTREAM},
    {"pauseenabled",          PLAYER_CAN_PAUSE},
    {"seekenabled",           PLAYER_CAN_SEEK},
    {"channelpreviewactive",  PLAYER_IS_CHANNEL_PREVIEW_ACTIVE},
    {"tempoenabled",          PLAYER_SUPPORTS_TEMPO},
    {"istempo",               PLAYER_IS_TEMPO},
    {"playspeed",             PLAYER_PLAYSPEED},
    {"hasprograms",           PLAYER_HAS_PROGRAMS},
    {"hasresolutions",        PLAYER_HAS_RESOLUTIONS},
    {"frameadvance",          PLAYER_FRAMEADVANCE},
    {"icon",                  PLAYER_ICON},
    {"editlist",              PLAYER_EDITLIST},
    {"cuts",                  PLAYER_CUTS},
    {"scenemarkers",          PLAYER_SCENE_MARKERS},
    {"hasscenemarkers",       PLAYER_HAS_SCENE_MARKERS},
    {"chapters",              PLAYER_CHAPTERS},
    {"bookmarks",             PLAYER_BOOKMARKS},
    {"hasbookmarks",          PLAYER_HAS_BOOKMARKS},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
///   \table_row3{   <b>`Player.Art(type)`</b>,
///                  \anchor Player_Art_type
///                  _string_,
///     @return The Image for the defined art type for the current playing ListItem.
///     @param type - The art type. The type is defined by scripts and scrappers and can have any value.
///     Common example values for type are:
///       - fanart
///       - thumb
///       - poster
///       - banner
///       - clearlogo
///       - tvshow.poster
///       - tvshow.banner
///       - etc
///     @todo get a way of centralize all random art strings used in core so we can point users to them
///     while still making it clear they can have any value.
///     <p>
///   }
///   \table_row3{   <b>`Player.HasPerformedSeek(interval)`</b>,
///                  \anchor Player_HasPerformedSeek
///                  _boolean_,
///     @return **True** if the Player has performed a seek operation in the last provided second `interval`\, **False** otherwise.
///     @param interval - the time interval (in seconds)
///     <p><hr>
///     @skinning_v20 **[New Boolean Condition]** \link Player_HasPerformedSeek `Player.HasPerformedSeek(interval)`\endlink
///     <p>
///   }
// clang-format off
constexpr std::array<InfoMap, 2> player_param = {{
    {"art",               PLAYER_ITEM_ART},
    {"hasperformedseek",  PLAYER_HASPERFORMEDSEEK},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
///   \table_row3{   <b>`Player.SeekTime`</b>,
///                  \anchor Player_SeekTime
///                  _string_,
///     @return The time to which the user is seeking.
///     <p>
///   }
///   \table_row3{   <b>`Player.SeekOffset([format])`</b>,
///                  \anchor Player_SeekOffset_format
///                  _string_,
///     @return The seek offset after a seek press in a given format.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///     @note **Example:** user presses BigStepForward\, player.seekoffset returns +10:00
///     <p>
///   }
///   \table_row3{   <b>`Player.SeekStepSize`</b>,
///                  \anchor Player_SeekStepSize
///                  _string_,
///     @return The seek step size.
///     <p>
///     <hr>
///     @skinning_v15 **[New Infolabel]** \link Player_SeekStepSize `Player.SeekStepSize`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.TimeRemaining([format])`</b>,
///                  \anchor Player_TimeRemaining_format
///                  _string_,
///     @return The remaining time of current playing media in a given format.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`Player.TimeSpeed`</b>,
///                  \anchor Player_TimeSpeed
///                  _string_,
///     @return The time and the playspeed formatted: "1:23 (2x)".
///     <p>
///   }
///   \table_row3{   <b>`Player.Time([format])`</b>,
///                  \anchor Player_Time_format
///                  _string_,
///     @return The elapsed time of current playing media in a given format.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`Player.Duration([format])`</b>,
///                  \anchor Player_Duration_format
///                  _string_,
///     @return The total duration of the current playing media in a given format.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`Player.FinishTime([format])`</b>,
///                  \anchor Player_FinishTime_format
///                  _string_,
///     @return The time at which the playing media will end (in a specified format).
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`Player.StartTime([format])`</b>,
///                  \anchor Player_StartTime_format
///                  _string_,
///     @return The time at which the playing media began (in a specified format).
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`Player.SeekNumeric([format])`</b>,
///                  \anchor Player_SeekNumeric_format
///                  _string_,
///     @return The time at which the playing media began (in a specified format).
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
// clang-format off
constexpr std::array<InfoMap, 10> player_times = {{
    {"seektime",      PLAYER_SEEKTIME},
    {"seekoffset",    PLAYER_SEEKOFFSET},
    {"seekstepsize",  PLAYER_SEEKSTEPSIZE},
    {"timeremaining", PLAYER_TIME_REMAINING},
    {"timespeed",     PLAYER_TIME_SPEED},
    {"time",          PLAYER_TIME},
    {"duration",      PLAYER_DURATION},
    {"finishtime",    PLAYER_FINISH_TIME},
    {"starttime",     PLAYER_START_TIME},
    {"seeknumeric",   PLAYER_SEEKNUMERIC},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
///   \table_row3{   <b>`Player.Process(videohwdecoder)`</b>,
///                  \anchor Player_Process_videohwdecoder
///                  _boolean_,
///     @return **True** if the currently playing video is decoded in hardware.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Player_Process_videohwdecoder `Player.Process(videohwdecoder)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(videodecoder)`</b>,
///                  \anchor Player_Process_videodecoder
///                  _string_,
///     @return The videodecoder name of the currently playing video.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_videodecoder `Player.Process(videodecoder)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(deintmethod)`</b>,
///                  \anchor Player_Process_deintmethod
///                  _string_,
///     @return The deinterlace method of the currently playing video.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_deintmethod `Player.Process(deintmethod)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(pixformat)`</b>,
///                  \anchor Player_Process_pixformat
///                  _string_,
///     @return The pixel format of the currently playing video.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_pixformat `Player.Process(pixformat)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(videowidth)`</b>,
///                  \anchor Player_Process_videowidth
///                  _string_,
///     @return The width of the currently playing video.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_videowidth `Player.Process(videowidth)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(videoheight)`</b>,
///                  \anchor Player_Process_videoheight
///                  _string_,
///     @return The width of the currently playing video.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_videoheight `Player.Process(videoheight)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(videoscantype)`</b>,
///                  \anchor Player_Process_videoscantype
///                  _string_,
///     @return The scan type identifier of the currently playing video **p** (for progressive) or **i** (for interlaced).
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link Player_Process_videoscantype `Player.Process(videoscantype)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(videofps)`</b>,
///                  \anchor Player_Process_videofps
///                  _string_,
///     @return The video framerate of the currently playing video.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_videofps `Player.Process(videofps)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(videodar)`</b>,
///                  \anchor Player_Process_videodar
///                  _string_,
///     @return The display aspect ratio of the currently playing video.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_videodar `Player.Process(videodar)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(audiodecoder)`</b>,
///                  \anchor Player_Process_audiodecoder
///                  _string_,
///     @return The audiodecoder name of the currently playing item.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_videodar `Player.Process(audiodecoder)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(audiochannels)`</b>,
///                  \anchor Player_Process_audiochannels
///                  _string_,
///     @return The audiochannels string of the currently playing item.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_audiochannels `Player.Process(audiochannels)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(audiosamplerate)`</b>,
///                  \anchor Player_Process_audiosamplerate
///                  _string_,
///     @return The samplerate of the currently playing item.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_audiosamplerate `Player.Process(audiosamplerate)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(audiobitspersample)`</b>,
///                  \anchor Player_Process_audiobitspersample
///                  _string_,
///     @return The bits per sample of the currently playing item.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Player_Process_audiobitspersample `Player.Process(audiobitspersample)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(audiolivebitrate)`</b>,
///                  \anchor Player_Process_audiolivebitrate
///                  _string_,
///     @return The live audio bitrate of the currently playing item\, including the localized speed unit of measure (ex. Kb/s)
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Player_Process_audiolivebitrate `Player.Process(audiolivebitrate)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(audioqueuelevel)`</b>,
///                  \anchor Player_Process_audioqueuelevel
///                  _string_,
///     @return The audio queue level of the currently playing item as a percentage.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Player_Process_audioqueuelevel `Player.Process(audioqueuelevel)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(audioqueuedatalevel)`</b>,
///                  \anchor Player_Process_audioqueuedatalevel
///                  _string_,
///     @return The audio queue data level of the currently playing item as a percentage.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Player_Process_audioqueuedatalevel `Player.Process(audioqueuedatalevel)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(videolivebitrate)`</b>,
///                  \anchor Player_Process_videolivebitrate
///                  _string_,
///     @return The live video bitrate of the currently playing item\, including the localized speed unit of measure (ex. Mb/s)
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Player_Process_videolivebitrate `Player.Process(videolivebitrate)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(videoqueuelevel)`</b>,
///                  \anchor Player_Process_videoqueuelevel
///                  _string_,
///     @return The video queue level of the currently playing item as a percentage.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Player_Process_videoqueuelevel `Player.Process(videoqueuelevel)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(videoqueuedatalevel)`</b>,
///                  \anchor Player_Process_videoqueuedatalevel
///                  _string_,
///     @return The video queue data level of the currently playing item as a percentage.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Player_Process_videoqueuedatalevel `Player.Process(videoqueuedatalevel)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Player.Process(subtitledecoder)`</b>,
///                  \anchor Player_Process_subtitledecoder
///                  _string_,
///     @return The name of the active subtitle decoder for the currently playing item\, for example
///             ff-pgssub or SSA Subtitle Decoder.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Player_Process_subtitledecoder `Player.Process(subtitledecoder)`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 20> player_process = {{
    {"videodecoder",        PLAYER_PROCESS_VIDEODECODER},
    {"deintmethod",         PLAYER_PROCESS_DEINTMETHOD},
    {"pixformat",           PLAYER_PROCESS_PIXELFORMAT},
    {"videowidth",          PLAYER_PROCESS_VIDEOWIDTH},
    {"videoheight",         PLAYER_PROCESS_VIDEOHEIGHT},
    {"videofps",            PLAYER_PROCESS_VIDEOFPS},
    {"videodar",            PLAYER_PROCESS_VIDEODAR},
    {"videohwdecoder",      PLAYER_PROCESS_VIDEOHWDECODER},
    {"audiodecoder",        PLAYER_PROCESS_AUDIODECODER},
    {"audiochannels",       PLAYER_PROCESS_AUDIOCHANNELS},
    {"audiosamplerate",     PLAYER_PROCESS_AUDIOSAMPLERATE},
    {"audiobitspersample",  PLAYER_PROCESS_AUDIOBITSPERSAMPLE},
    {"audiolivebitrate",    PLAYER_PROCESS_AUDIO_LIVE_BITRATE},
    {"audioqueuelevel",     PLAYER_PROCESS_AUDIO_QUEUE_LEVEL},
    {"audioqueuedatalevel", PLAYER_PROCESS_AUDIO_QUEUE_DATA_LEVEL},
    {"videolivebitrate",    PLAYER_PROCESS_VIDEO_LIVE_BITRATE},
    {"videoqueuelevel",     PLAYER_PROCESS_VIDEO_QUEUE_LEVEL},
    {"videoqueuedatalevel", PLAYER_PROCESS_VIDEO_QUEUE_DATA_LEVEL},
    {"videoscantype",       PLAYER_PROCESS_VIDEOSCANTYPE},
    {"subtitledecoder",     PLAYER_PROCESS_SUBTITLEDECODER},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Weather Weather
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Weather.IsFetched`</b>,
///                  \anchor Weather_IsFetched
///                  _boolean_,
///     @return **True** if the weather data has been downloaded.
///     <p>
///   }
///   \table_row3{   <b>`Weather.IsUpdating`</b>,
///                  \anchor Weather_IsUpdating
///                  _boolean_,
///     @return **True** if weather data are currently updating.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Weather_IsUpdating `Weather.IsUpdating`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Weather.LastUpdated`</b>,
///                  \anchor Weather_LastUpdated
///                  _string_,
///     @return The localized date and time weather data were last updated\, empty string if not available.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Weather_LastUpdated `Weather.LastUpdated`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Weather.Data(property)`</b>,
///                  \anchor Weather_Data
///                  _string_,
///     @return Weather data\, as specified by the parameter.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link Weather_Data `Weather.Data(property)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Weather.Conditions`</b>,
///                  \anchor Weather_Conditions
///                  _string_,
///     @return The current weather conditions as textual description.
///     <p>
///   }
///   \table_row3{   <b>`Weather.ConditionsIcon`</b>,
///                  \anchor Weather_ConditionsIcon
///                  _string_,
///     @return The current weather conditions as an icon.
///     <p>
///   }
///   \table_row3{   <b>`Weather.Temperature`</b>,
///                  \anchor Weather_Temperature
///                  _string_,
///     @return The current weather temperature.
///     <p>
///   }
///   \table_row3{   <b>`Weather.Location`</b>,
///                  \anchor Weather_Location
///                  _string_,
///     @return The city/town which the above two items are for.
///     <p>
///   }
///   \table_row3{   <b>`Weather.Fanartcode`</b>,
///                  \anchor Weather_fanartcode
///                  _string_,
///     @return The current weather fanartcode.
///     <p>
///   }
///   \table_row3{   <b>`Weather.Plugin`</b>,
///                  \anchor Weather_plugin
///                  _string_,
///     @return The current weather plugin.
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 10> weather = {{
    {"isfetched",       WEATHER_IS_FETCHED},
    {"isupdating",      WEATHER_IS_UPDATING},
    {"lastupdated",     WEATHER_LAST_UPDATED}, // labels from here
    {"data",            WEATHER_DATA},
    {"conditions",      WEATHER_CONDITIONS_TEXT},
    {"temperature",     WEATHER_TEMPERATURE},
    {"location",        WEATHER_LOCATION},
    {"fanartcode",      WEATHER_FANART_CODE},
    {"plugin",          WEATHER_PLUGIN},
    {"conditionsicon",  WEATHER_CONDITIONS_ICON},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_System System
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`System.AlarmLessOrEqual(alarmname\,seconds)`</b>,
///                  \anchor System_AlarmLessOrEqual
///                  _boolean_,
///     @return **True** if the alarm with `alarmname` has less or equal to `seconds` left.
///     @param alarmname - The name of the alarm. It can be one of the following:
///       - shutdowntimer
///     @param seconds - Time in seconds to compare with the alarm trigger event
///     @note **Example:** `System.Alarmlessorequal(shutdowntimer\,119)`\,
///     will return true when the shutdowntimer has less then 2 minutes
///     left.
///     <p>
///   }
///   \table_row3{   <b>`System.HasNetwork`</b>,
///                  \anchor System_HasNetwork
///                  _boolean_,
///     @return **True** if the Kodi host has a network available.
///     @note This feature is NOT implemented. Always returns true
///     <p>
///   }
///   \table_row3{   <b>`System.HasMediadvd`</b>,
///                  \anchor System_HasMediadvd
///                  _boolean_,
///     @return **True** if there is a CD or DVD in the DVD-ROM drive.
///     <p>
///   }
///   \table_row3{   <b>`System.HasMediaAudioCD`</b>,
///                  \anchor System_HasMediaAudioCD
///                  _boolean_,
///     @return **True** if there is an audio CD in the optical drive. **False** if no drive
///     available\, empty drive or other medium.
///   <p><hr>
///   @skinning_v18 **[New Boolean Condition]** \link System_HasMediaAudioCD
///   `System.HasMediaAudioCD` \endlink <p>
///   }
///   \table_row3{   <b>`System.HasMediaBlurayPlaylist`</b>,
///                  \anchor System_HasMediaBlurayPlaylist
///                  _boolean_,
///     @return **True** if there is a bluray in the drive that has been played before.
///     **False** if no drive available\, empty drive\, other medium or new bluray.
///   <p><hr>
///   @skinning_v18 **[New Boolean Condition]** \link System_HasMediaBlurayPlaylist
///   `System.System_HasMediaBlurayPlaylist` \endlink <p>
///   }
///   \table_row3{   <b>`System.DVDReady`</b>,
///                  \anchor System_DVDReady
///                  _boolean_,
///     @return **True** if the disc is ready to use.
///     <p>
///   }
///   \table_row3{   <b>`System.TrayOpen`</b>,
///                  \anchor System_TrayOpen
///                  _boolean_,
///     @return **True** if the disc tray is open.
///     <p>
///   }
///   \table_row3{   <b>`System.HasLocks`</b>,
///                  \anchor System_HasLocks
///                  _boolean_,
///     @return **True** if the system has an active lock mode.
///     <p>
///   }
///   \table_row3{   <b>`System.IsMaster`</b>,
///                  \anchor System_IsMaster
///                  _boolean_,
///     @return **True** if the system is in master mode.
///     <p>
///   }
///   \table_row3{   <b>`System.ShowExitButton`</b>,
///                  \anchor System_ShowExitButton
///                  _boolean_,
///     @return **True** if the exit button should be shown (configurable via advanced settings).
///     <p>
///   }
///   \table_row3{   <b>`System.DPMSActive`</b>,
///                  \anchor System_DPMSActive
///                  _boolean_,
///     @return **True** if DPMS (VESA Display Power Management Signaling) mode is active.
///     <p>
///   }
///   \table_row3{   <b>`System.IsStandalone`</b>,
///                  \anchor System_IsStandalone
///                  _boolean_,
///     @return **True** if Kodi is running in standalone mode.
///     <p>
///   }
///   \table_row3{   <b>`System.IsFullscreen`</b>,
///                  \anchor System_IsFullscreen
///                  _boolean_,
///     @return **True** if Kodi is running fullscreen.
///     <p>
///   }
///   \table_row3{   <b>`System.LoggedOn`</b>,
///                  \anchor System_LoggedOn
///                  _boolean_,
///     @return **True** if a user is currently logged on under a profile.
///     <p>
///   }
///   \table_row3{   <b>`System.HasLoginScreen`</b>,
///                  \anchor System_HasLoginScreen
///                  _boolean_,
///     @return **True** if the profile login screen is enabled.
///     <p>
///   }
///   \table_row3{   <b>`System.HasPVR`</b>,
///                  \anchor System_HasPVR
///                  _boolean_,
///     @return **True** if PVR is supported from Kodi.
///     @note normally always true
///
///   }
///   \table_row3{   <b>`System.HasPVRAddon`</b>,
///                  \anchor System_HasPVRAddon
///                  _boolean_,
///     @return **True** if at least one pvr client addon is installed and enabled.
///     @param id - addon id of the PVR addon
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link System_HasPVRAddon
///     `System.HasPVRAddon`\endlink <p>
///   }
///   \table_row3{   <b>`System.HasCMS`</b>,
///                  \anchor System_HasCMS
///                  _boolean_,
///     @return **True** if colour management is supported from Kodi.
///     @note currently only supported for OpenGL
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link System_HasCMS `System.HasCMS`\endlink
///     <p>
///   }
///   \table_row3{   <b>`System.HasActiveModalDialog`</b>,
///                  \anchor System_HasActiveModalDialog
///                  _boolean_,
///     @return **True** if a modal dialog is active.
///     <p><hr>
///     @skinning_v18 **[New Boolean Condition]** \link System_HasActiveModalDialog
///     `System.HasActiveModalDialog`\endlink <p>
///   }
///   \table_row3{   <b>`System.HasVisibleModalDialog`</b>,
///                  \anchor System_HasVisibleModalDialog
///                  _boolean_,
///     @return **True** if a modal dialog is visible.
///     <p><hr>
///     @skinning_v18 **[New Boolean Condition]** \link System_HasVisibleModalDialog
///     `System.HasVisibleModalDialog`\endlink <p>
///   }
///   \table_row3{   <b>`System.Platform.Linux`</b>,
///                  \anchor System_PlatformLinux
///                  _boolean_,
///     @return **True** if Kodi is running on a linux/unix based computer.
///     <p>
///   }
///   \table_row3{   <b>`System.Platform.Windows`</b>,
///                  \anchor System_PlatformWindows
///                  _boolean_,
///     @return **True** if Kodi is running on a windows based computer.
///     <p>
///   }
///   \table_row3{   <b>`System.Platform.UWP`</b>,
///                  \anchor System_PlatformUWP
///                  _boolean_,
///     @return **True** if Kodi is running on Universal Windows Platform (UWP).
///     <p><hr>
///     @skinning_v18 **[New Boolean Condition]** \link System_PlatformUWP
///     `System.Platform.UWP`\endlink <p>
///   }
///   \table_row3{   <b>`System.Platform.OSX`</b>,
///                  \anchor System_PlatformOSX
///                  _boolean_,
///     @return **True** if Kodi is running on an OSX based computer.
///     <p>
///   }
///   \table_row3{   <b>`System.Platform.IOS`</b>,
///                  \anchor System_PlatformIOS
///                  _boolean_,
///     @return **True** if Kodi is running on an IOS device.
///     <p>
///   }
///   \table_row3{   <b>`System.Platform.TVOS`</b>,
///                  \anchor System_PlatformTVOS
///                  _boolean_,
///     @return **True** if Kodi is running on a tvOS device.
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link System_PlatformTVOS
///     `System.Platform.TVOS`\endlink <p>
///   }
///   \table_row3{   <b>`System.Platform.Darwin`</b>,
///                  \anchor System_PlatformDarwin
///                  _boolean_,
///     @return **True** if Kodi is running on an OSX or IOS system.
///     <p>
///   }
///   \table_row3{   <b>`System.Platform.Android`</b>,
///                  \anchor System_PlatformAndroid
///                  _boolean_,
///     @return **True** if Kodi is running on an android device.
///     <p>
///   }
///   \table_row3{   <b>`System.Platform.WebOS`</b>,
///                  \anchor System_PlatformWebOS
///                  _boolean_,
///     @return **True** if Kodi is running on a WebOS device.
///     <p><hr>
///     @skinning_v21 **[New Boolean Condition]** \link System_PlatformWebOS
///     `System.Platform.WebOS`\endlink <p>
///   }
///   \table_row3{   <b>`System.CanPowerDown`</b>,
///                  \anchor System_CanPowerDown
///                  _boolean_,
///     @return **True** if Kodi can powerdown the system.
///     <p>
///   }
///   \table_row3{   <b>`System.CanSuspend`</b>,
///                  \anchor System_CanSuspend
///                  _boolean_,
///     @return **True** if Kodi can suspend the system.
///     <p>
///   }
///   \table_row3{   <b>`System.CanHibernate`</b>,
///                  \anchor System_CanHibernate
///                  _boolean_,
///     @return **True** if Kodi can hibernate the system.
///     <p>
///   }
///   \table_row3{   <b>`System.HasHiddenInput`</b>,
///                  \anchor System_HasHiddenInput
///                  _boolean_,
///     @return **True** when to osd keyboard/numeric dialog requests a
///     password/pincode.
///     <p><hr>
///     @skinning_v16 **[New Boolean Condition]** \link System_HasHiddenInput
///     `System.HasHiddenInput`\endlink <p>
///   }
///   \table_row3{   <b>`System.CanReboot`</b>,
///                  \anchor System_CanReboot
///                  _boolean_,
///     @return **True** if Kodi can reboot the system.
///     <p>
///   }
///   \table_row3{   <b>`System.ScreenSaverActive`</b>,
///                  \anchor System_ScreenSaverActive
///                  _boolean_,
///     @return **True** if ScreenSaver is active.
///     <p>
///   }
///   \table_row3{   <b>`System.IdleShutdownInhibited`</b>,
///                  \anchor System_IdleShutdownInhibited
///                  _boolean_,
///     @return **True** when shutdown on idle is disabled.
///     <p>
///   }
///   \table_row3{   <b>`System.HasShutdown`</b>,
///                  \anchor System_HasShutdown
///                  _boolean_,
///     @return **True** if Kodi can shutdown the system.
///     <p>
///   }
///   \table_row3{   <b>`System.Time`</b>,
///                  \anchor System_Time
///                  _string_,
///     @return The current time.
///     <p>
///   }
///   \table_row3{   <b>`System.Time(format)`</b>,
///                  \anchor System_Time_format
///                  _string_,
///     @return The current time in a specified format.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`System.Time(startTime[\,endTime])`</b>,
///                  \anchor System_Time_startTime_endTime
///                  _boolean_,
///     @return **True** if the current system time is >= `startTime` and < `endTime` (if defined).
///     @param startTime - Start time
///     @param endTime - [opt] End time
///     <p>
///     @note Time must be specified in the format HH:mm\, using
///     a 24 hour clock.
///     <p>
///   }
///   \table_row3{   <b>`System.Date`</b>,
///                  \anchor System_Date
///                  _string_,
///     @return The current date.
///     <p><hr>
///     @skinning_v16 **[Infolabel Updated]** \link System_Date `System.Date`\endlink
///     will now return the full day and month names. old: sat\, jul 18 2015
///     new: saturday\, july 18 2015
///     <p>
///   }
///   \table_row3{   <b>`System.Date(format)`</b>,
///                  \anchor System_Date_format
///                  _string_,
///     @return The current date using a specified format.
///     @param format - the format for the date. It can be one of the following
///     values:
///       - **d** - day of month (1-31)
///       - **dd** - day of month (01-31)
///       - **ddd** - short day of the week Mon-Sun
///       - **DDD** - long day of the week Monday-Sunday
///       - **m** - month (1-12)
///       - **mm** - month (01-12)
///       - **mmm** - short month name Jan-Dec
///       - **MMM** - long month name January-December
///       - **yy** - 2-digit year
///       - **yyyy** - 4-digit year
///     <p>
///   }
///   \table_row3{   <b>`System.Date(startDate[\,endDate])`</b>,
///                  \anchor System_Date_startDate_endDate
///                  _boolean_,
///     @return **True** if the current system date is >= `startDate` and < `endDate` (if defined).
///     @param startDate - The start date
///     @param endDate - [opt] The end date
///     @note Date must be specified in the format MM-DD or YY-MM-DD.
///     <p>
///   }
///   \table_row3{   <b>`System.AlarmPos`</b>,
///                  \anchor System_AlarmPos
///                  _string_,
///     @return The shutdown Timer position.
///     <p>
///   }
///   \table_row3{   <b>`System.BatteryLevel`</b>,
///                  \anchor System_BatteryLevel
///                  _string_,
///     @return The remaining battery level in range 0-100.
///     <p>
///   }
///   \table_row3{   <b>`System.FreeSpace`</b>,
///                  \anchor System_FreeSpace
///                  _string_,
///     @return The total Freespace on the drive.
///     <p>
///   }
///   \table_row3{   <b>`System.UsedSpace`</b>,
///                  \anchor System_UsedSpace
///                  _string_,
///     @return The total Usedspace on the drive.
///     <p>
///   }
///   \table_row3{   <b>`System.TotalSpace`</b>,
///                  \anchor System_TotalSpace
///                  _string_,
///     @return The total space on the drive.
///     <p>
///   }
///   \table_row3{   <b>`System.UsedSpacePercent`</b>,
///                  \anchor System_UsedSpacePercent
///                  _string_,
///     @return The total Usedspace Percent on the drive.
///     <p>
///   }
///   \table_row3{   <b>`System.FreeSpacePercent`</b>,
///                  \anchor System_FreeSpacePercent
///                  _string_,
///     @return The total Freespace Percent on the drive.
///     <p>
///   }
///   \table_row3{   <b>`System.CPUTemperature`</b>,
///                  \anchor System_CPUTemperature
///                  _string_,
///     @return The current CPU temperature.
///     <p>
///   }
///   \table_row3{   <b>`System.CpuUsage`</b>,
///                  \anchor System_CpuUsage
///                  _string_,
///     @return The the cpu usage for each individual cpu core.
///     <p>
///   }
///   \table_row3{   <b>`System.GPUTemperature`</b>,
///                  \anchor System_GPUTemperature
///                  _string_,
///     @return The current GPU temperature.
///     <p>
///   }
///   \table_row3{   <b>`System.FanSpeed`</b>,
///                  \anchor System_FanSpeed
///                  _string_,
///     @return The current fan speed.
///     <p>
///   }
///   \table_row3{   <b>`System.BuildVersion`</b>,
///                  \anchor System_BuildVersion
///                  _string_,
///     @return The version of build.
///     <p>
///   }
///   \table_row3{   <b>`System.BuildVersionShort`</b>,
///                  \anchor System_BuildVersionShort
///                  _string_,
///     @return The shorter string with version of build.
///     <p>
///   }
///   \table_row3{   <b>`System.BuildDate`</b>,
///                  \anchor System_BuildDate
///                  _string_,
///     @return The date of build.
///     <p>
///   }
///   \table_row3{   <b>`System.BuildVersionCode`</b>,
///                  \anchor System_BuildVersionCode
///                  _string_,
///     @return The version code of build.
///     <p>
///   }
///   \table_row3{   <b>`System.BuildVersionGit`</b>,
///                  \anchor System_BuildVersionGit
///                  _string_,
///     @return The git version of build.
///     <p>
///   }
///   \table_row3{   <b>`System.FriendlyName`</b>,
///                  \anchor System_FriendlyName
///                  _string_,
///     @return The Kodi instance name.
///     @note It will auto append (%hostname%) in case
///     the device name was not changed. eg. "Kodi (htpc)"
///     <p>
///   }
///   \table_row3{   <b>`System.FPS`</b>,
///                  \anchor System_FPS
///                  _string_,
///     @return The current rendering speed (frames per second).
///     <p>
///   }
///   \table_row3{   <b>`System.FreeMemory`</b>,
///                  \anchor System_FreeMemory
///                  _string_,
///     @return The amount of free memory in Mb.
///     <p>
///   }
///   \table_row3{   <b>`System.ScreenMode`</b>,
///                  \anchor System_ScreenMode
///                  _string_,
///     @return The screenmode (eg windowed / fullscreen).
///     <p>
///   }
///   \table_row3{   <b>`System.ScreenWidth`</b>,
///                  \anchor System_ScreenWidth
///                  _string_,
///     @return The width of screen in pixels.
///     <p>
///   }
///   \table_row3{   <b>`System.ScreenHeight`</b>,
///                  \anchor System_ScreenHeight
///                  _string_,
///     @return The height of screen in pixels.
///     <p>
///   }
///   \table_row3{   <b>`System.StartupWindow`</b>,
///                  \anchor System_StartupWindow
///                  _string_,
///     @return The Window Kodi will load on startup.
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link System_StartupWindow `System.StartupWindow`\endlink
///     <p>
///   }
///   \table_row3{   <b>`System.CurrentWindow`</b>,
///                  \anchor System_CurrentWindow
///                  _string_,
///     @return The current Window in use.
///     <p>
///   }
///   \table_row3{   <b>`System.CurrentControl`</b>,
///                  \anchor System_CurrentControl
///                  _string_,
///     @return The current focused control
///     <p>
///   }
///   \table_row3{   <b>`System.CurrentControlId`</b>,
///                  \anchor System_CurrentControlId
///                  _string_,
///     @return The ID of the currently focused control.
///     <p>
///   }
///   \table_row3{   <b>`System.DVDLabel`</b>,
///                  \anchor System_DVDLabel
///                  _string_,
///     @return the label of the disk in the DVD-ROM drive.
///     <p>
///   }
///   \table_row3{   <b>`System.KernelVersion`</b>,
///                  \anchor System_KernelVersion
///                  _string_,
///     @return The System kernel version.
///     <p>
///   }
///   \table_row3{   <b>`System.OSVersionInfo`</b>,
///                  \anchor System_OSVersionInfo
///                  _string_,
///     @return The system name + kernel version.
///     <p>
///   }
///   \table_row3{   <b>`System.Uptime`</b>,
///                  \anchor System_Uptime
///                  _string_,
///     @return The system current uptime.
///     <p>
///   }
///   \table_row3{   <b>`System.TotalUptime`</b>,
///                  \anchor System_TotalUptime
///                  _string_,
///     @return The system total uptime.
///     <p>
///   }
///   \table_row3{   <b>`System.CpuFrequency`</b>,
///                  \anchor System_CpuFrequency
///                  _string_,
///     @return The system cpu frequency.
///     <p>
///   }
///   \table_row3{   <b>`System.ScreenResolution`</b>,
///                  \anchor System_ScreenResolution
///                  _string_,
///     @return The screen resolution.
///     <p>
///   }
///   \table_row3{   <b>`System.VideoEncoderInfo`</b>,
///                  \anchor System_VideoEncoderInfo
///                  _string_,
///     @return The video encoder info.
///     <p>
///   }
///   \table_row3{   <b>`System.InternetState`</b>,
///                  \anchor System_InternetState
///                  _string_,
///     @return The internet state: connected or not connected.
///     @warning Do not use to check status in a pythonscript since it is threaded.
///     <p>
///   }
///   \table_row3{   <b>`System.Language`</b>,
///                  \anchor System_Language
///                  _string_,
///     @return the current language.
///     <p>
///   }
///   \table_row3{   <b>`System.Locale(type)`</b>,
///                  \anchor System_Locale
///                  _string_,
///     @return Locale-specific information depending on the requested type.
///     @param type - Can be one of the following:
///       - <b>region</b> The currently selected region name within the selected language ( \link System_Language `System.Language` \endlink).
///       - <b>iso</b> The country code of the currently selected region as specified in <a href="https://kodi.wiki/view/Language_support#What_is_langinfo.xml">langinfo.xml</a>.
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link System_Locale
///     `System.Locale(type)`\endlink
///     <p>
///     @skinning_v22 **[Removed options]** `timezonecountry` and `timezone` from \link System_Locale
///     `System.Locale(type)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`System.ProfileName`</b>,
///                  \anchor System_ProfileName
///                  _string_,
///     @return The user name of the currently logged in Kodi user
///     <p>
///   }
///   \table_row3{   <b>`System.ProfileThumb`</b>,
///                  \anchor System_ProfileThumb
///                  _string_,
///     @return The thumbnail image of the currently logged in Kodi user
///     <p>
///   }
///   \table_row3{   <b>`System.ProfileCount`</b>,
///                  \anchor System_ProfileCount
///                  _string_,
///     @return The number of defined profiles.
///     <p>
///   }
///   \table_row3{   <b>`System.ProfileAutoLogin`</b>,
///                  \anchor System_ProfileAutoLogin
///                  _string_,
///     @return The profile Kodi will auto login to.
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link System_ProfileAutoLogin
///     `System.ProfileAutoLogin`\endlink <p>
///   }
///   \table_row3{   <b>`System.StereoscopicMode`</b>,
///                  \anchor System_StereoscopicMode
///                  _string_,
///     @return The preferred stereoscopic mode.
///     @note Configured in settings > video > playback).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link System_StereoscopicMode
///     `System.StereoscopicMode`\endlink <p>
///   }
///   \table_row3{   <b>`System.TemperatureUnits`</b>,
///                  \anchor System_TemperatureUnits
///                  _string_,
///     @return the Celsius or the Fahrenheit symbol.
///     <p>
///   }
///   \table_row3{   <b>`System.Progressbar`</b>,
///                  \anchor System_Progressbar
///                  _string_,
///     @return The percentage of the currently active progress.
///     <p>
///   }
///   \table_row3{   <b>`System.GetBool(boolean)`</b>,
///                  \anchor System_GetBool
///                  _string_,
///     @return The value of any standard system boolean setting.
///     @note Will not work with settings in advancedsettings.xml
///     <p>
///   }
///   \table_row3{   <b>`System.Memory(type)`</b>,
///                  \anchor System_Memory
///                  _string_,
///     @return The memory value depending on the requested type.
///     @param type - Can be one of the following:
///       - <b>free</b>
///       - <b>free.percent</b>
///       - <b>used</b>
///       - <b>used.percent</b>
///       - <b>total</b>
///     <p>
///   }
///   \table_row3{   <b>`System.AddonTitle(id)`</b>,
///                  \anchor System_AddonTitle
///                  _string_,
///     @return The title of the addon with the given id
///     @param id - the addon id
///     <p>
///   }
///   \table_row3{   <b>`System.AddonVersion(id)`</b>,
///                  \anchor System_AddonVersion
///                  _string_,
///     @return The version of the addon with the given id.
///     @param id - the addon id
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link System_AddonVersion
///     `System.AddonVersion(id)`\endlink <p>
///   }
///   \table_row3{   <b>`System.AddonIcon(id)`</b>,
///                  \anchor System_AddonIcon
///                  _string_,
///     @return The icon of the addon with the given id.
///     @param id - the addon id
///     <p>
///   }
///   \table_row3{   <b>`System.AddonUpdateCount`</b>,
///                  \anchor System_AddonUpdateCount
///                  _string_,
///     @return The number of available addon updates.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link  System_AddonUpdateCount `
///     System.AddonUpdateCount`\endlink <p>
///   }
///   \table_row3{   <b>`System.IdleTime(time)`</b>,
///                  \anchor System_IdleTime
///                  _boolean_,
///     @return **True** if Kodi has had no input for `time` amount of seconds.
///     @param time - elapsed seconds to check for idle activity.
///     <p>
///   }
///   \table_row3{   <b>`System.PrivacyPolicy`</b>,
///                  \anchor System_PrivacyPolicy
///                  _string_,
///     @return The official Kodi privacy policy.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link System_PrivacyPolicy `System.PrivacyPolicy`\endlink
///     <p>
///   }
///   \table_row3{   <b>`System.SupportsCPUUsage`</b>,
///                  \anchor System_SupportsCPUUsage
///                  _boolean_,
///     @return **True** if the system can provide CPU usage information.
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link  System_SupportsCPUUsage `
///     System.SupportsCPUUsage`\endlink <p>
///   }
///   \table_row3{   <b>`System.SupportedHDRTypes`</b>,
///                  \anchor System_SupportedHDRTypes
///                  _string_,
///     @return The display's supported HDR types.
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link System_SupportedHDRTypes `System.SupportedHDRTypes`\endlink
///     <p>
///   }
///   \table_row3{   <b>`System.IsScreensaverInhibited`</b>,
///                  \anchor System_IsScreensaverInhibited
///                  _boolean_,
///     @return **True** when screensaver on idle is disabled.
///     <p>
///   }
// clang-format off
constexpr std::array<InfoMap, 76> system_labels = {{
    {"hasnetwork",              SYSTEM_ETHERNET_LINK_ACTIVE},
    {"hasmediadvd",             SYSTEM_MEDIA_DVD},
    {"hasmediaaudiocd",         SYSTEM_MEDIA_AUDIO_CD},
    {"hasmediablurayplaylist",  SYSTEM_MEDIA_BLURAY_PLAYLIST},
    {"dvdready",                SYSTEM_DVDREADY},
    {"trayopen",                SYSTEM_TRAYOPEN},
    {"haslocks",                SYSTEM_HASLOCKS},
    {"hashiddeninput",          SYSTEM_HAS_INPUT_HIDDEN},
    {"hasloginscreen",          SYSTEM_HAS_LOGINSCREEN},
    {"hasactivemodaldialog",    SYSTEM_HAS_ACTIVE_MODAL_DIALOG},
    {"hasvisiblemodaldialog",   SYSTEM_HAS_VISIBLE_MODAL_DIALOG},
    {"ismaster",                SYSTEM_ISMASTER},
    {"isfullscreen",            SYSTEM_ISFULLSCREEN},
    {"isstandalone",            SYSTEM_ISSTANDALONE},
    {"loggedon",                SYSTEM_LOGGEDON},
    {"showexitbutton",          SYSTEM_SHOW_EXIT_BUTTON},
    {"canpowerdown",            SYSTEM_CAN_POWERDOWN},
    {"cansuspend",              SYSTEM_CAN_SUSPEND},
    {"canhibernate",            SYSTEM_CAN_HIBERNATE},
    {"canreboot",               SYSTEM_CAN_REBOOT},
    {"screensaveractive",       SYSTEM_SCREENSAVER_ACTIVE},
    {"dpmsactive",              SYSTEM_DPMS_ACTIVE},
    {"cputemperature",          SYSTEM_CPU_TEMPERATURE}, // labels from here
    {"cpuusage",                SYSTEM_CPU_USAGE},
    {"gputemperature",          SYSTEM_GPU_TEMPERATURE},
    {"fanspeed",                SYSTEM_FAN_SPEED},
    {"freespace",               SYSTEM_FREE_SPACE},
    {"usedspace",               SYSTEM_USED_SPACE},
    {"totalspace",              SYSTEM_TOTAL_SPACE},
    {"usedspacepercent",        SYSTEM_USED_SPACE_PERCENT},
    {"freespacepercent",        SYSTEM_FREE_SPACE_PERCENT},
    {"buildversion",            SYSTEM_BUILD_VERSION},
    {"buildversionshort",       SYSTEM_BUILD_VERSION_SHORT},
    {"buildversioncode",        SYSTEM_BUILD_VERSION_CODE},
    {"buildversiongit",         SYSTEM_BUILD_VERSION_GIT},
    {"builddate",               SYSTEM_BUILD_DATE},
    {"fps",                     SYSTEM_FPS},
    {"freememory",              SYSTEM_FREE_MEMORY},
    {"language",                SYSTEM_LANGUAGE},
    {"temperatureunits",        SYSTEM_TEMPERATURE_UNITS},
    {"screenmode",              SYSTEM_SCREEN_MODE},
    {"screenwidth",             SYSTEM_SCREEN_WIDTH},
    {"screenheight",            SYSTEM_SCREEN_HEIGHT},
    {"currentwindow",           SYSTEM_CURRENT_WINDOW},
    {"currentcontrol",          SYSTEM_CURRENT_CONTROL},
    {"currentcontrolid",        SYSTEM_CURRENT_CONTROL_ID},
    {"dvdlabel",                SYSTEM_DVD_LABEL},
    {"internetstate",           SYSTEM_INTERNET_STATE},
    {"osversioninfo",           SYSTEM_OS_VERSION_INFO},
    {"kernelversion",           SYSTEM_OS_VERSION_INFO}, // old, not correct name
    {"uptime",                  SYSTEM_UPTIME},
    {"totaluptime",             SYSTEM_TOTALUPTIME},
    {"cpufrequency",            SYSTEM_CPUFREQUENCY},
    {"screenresolution",        SYSTEM_SCREEN_RESOLUTION},
    {"videoencoderinfo",        SYSTEM_VIDEO_ENCODER_INFO},
    {"profilename",             SYSTEM_PROFILENAME},
    {"profilethumb",            SYSTEM_PROFILETHUMB},
    {"profilecount",            SYSTEM_PROFILECOUNT},
    {"profileautologin",        SYSTEM_PROFILEAUTOLOGIN},
    {"progressbar",             SYSTEM_PROGRESS_BAR},
    {"batterylevel",            SYSTEM_BATTERY_LEVEL},
    {"friendlyname",            SYSTEM_FRIENDLY_NAME},
    {"alarmpos",                SYSTEM_ALARM_POS},
    {"isinhibit",               SYSTEM_IDLE_SHUTDOWN_INHIBITED}, //! @deprecated, replaced by "idleshutdowninhibited"
    {"idleshutdowninhibited",   SYSTEM_IDLE_SHUTDOWN_INHIBITED},
    {"hasshutdown",             SYSTEM_HAS_SHUTDOWN},
    {"haspvr",                  SYSTEM_HAS_PVR},
    {"startupwindow",           SYSTEM_STARTUP_WINDOW},
    {"stereoscopicmode",        SYSTEM_STEREOSCOPIC_MODE},
    {"hascms",                  SYSTEM_HAS_CMS},
    {"privacypolicy",           SYSTEM_PRIVACY_POLICY},
    {"haspvraddon",             SYSTEM_HAS_PVR_ADDON},
    {"addonupdatecount",        SYSTEM_ADDON_UPDATE_COUNT},
    {"supportscpuusage",        SYSTEM_SUPPORTS_CPU_USAGE},
    {"supportedhdrtypes",       SYSTEM_SUPPORTED_HDR_TYPES},
    {"isscreensaverinhibited",  SYSTEM_IS_SCREENSAVER_INHIBITED},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
///   \table_row3{   <b>`System.HasAddon(id)`</b>,
///                  \anchor System_HasAddon
///                  _boolean_,
///     @return **True** if the specified addon is installed on the system.
///     @param id - the addon id
///     @skinning_v19 **[Boolean Condition Updated]** \link System_HasAddon `System.HasAddon(id)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`System.AddonIsEnabled(id)`</b>,
///                  \anchor System_AddonIsEnabled
///                  _boolean_,
///     @return **True** if the specified addon is enabled on the system.
///     @param id - The addon Id
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link System_AddonIsEnabled `System.AddonIsEnabled(id)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`System.HasCoreId(id)`</b>,
///                  \anchor System_HasCoreId
///                  _boolean_,
///     @return **True** if the CPU core with the given 'id' exists.
///     @param id - the id of the CPU core
///     <p>
///   }
///   \table_row3{   <b>`System.HasAlarm(alarm)`</b>,
///                  \anchor System_HasAlarm
///                  _boolean_,
///     @return **True** if the system has the `alarm` alarm set.
///     @param alarm - the name of the alarm
///     <p>
///   }
///   \table_row3{   <b>`System.CoreUsage(id)`</b>,
///                  \anchor System_CoreUsage
///                  _string_,
///     @return the usage of the CPU core with the given 'id'
///     @param id - the id of the CPU core
///     <p>
///   }
///   \table_row3{   <b>`System.Setting(hidewatched)`</b>,
///                  \anchor System_Setting
///                  _boolean_,
///     @return **True** if 'hide watched items' is selected.
///     <p>
///   }
///   \table_row3{   <b>`System.Setting(hideunwatchedepisodethumbs)`</b>,
///                  \anchor System_Setting_HideUnwatchedEpisodeThumbs
///                  _boolean_,
///     @return **True** if 'hide unwatched episode setting is enabled'\, **False** otherwise.
///     <p><hr>
///     @skinning_v20 **[New Boolean Condition]** \link System_Setting_HideUnwatchedEpisodeThumbs `System.Setting(hideunwatchedepisodethumbs)`\endlink
///     <p>
///   }
/// \table_end
/// @todo Some values are hardcoded in the middle of the code  - refactor to make it easier to track
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 6> system_param = {{
    {"hasalarm",        SYSTEM_HAS_ALARM},
    {"hascoreid",       SYSTEM_HAS_CORE_ID},
    {"setting",         SYSTEM_SETTING},
    {"hasaddon",        SYSTEM_HAS_ADDON},
    {"addonisenabled",  SYSTEM_ADDON_IS_ENABLED},
    {"coreusage",       SYSTEM_GET_CORE_USAGE},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Network Network
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Network.IsDHCP`</b>,
///                  \anchor Network_IsDHCP
///                  _boolean_,
///     @return **True** if the network type is DHCP.
///     @note Network type can be either DHCP or FIXED
///     <p>
///   }
///   \table_row3{   <b>`Network.IPAddress`</b>,
///                  \anchor Network_IPAddress
///                  _string_,
///     @return The system's IP Address. e.g. 192.168.1.15
///     <p>
///   }
///   \table_row3{   <b>`Network.LinkState`</b>,
///                  \anchor Network_LinkState
///                  _string_,
///     @return The network linkstate e.g. 10mbit/100mbit etc.
///     <p>
///   }
///   \table_row3{   <b>`Network.MacAddress`</b>,
///                  \anchor Network_MacAddress
///                  _string_,
///     @return The system's MAC address.
///     <p>
///   }
///   \table_row3{   <b>`Network.SubnetMask`</b>,
///                  \anchor Network_SubnetMask
///                  _string_,
///     @return The network subnet mask.
///     <p>
///   }
///   \table_row3{   <b>`Network.GatewayAddress`</b>,
///                  \anchor Network_GatewayAddress
///                  _string_,
///     @return The network gateway address.
///     <p>
///   }
///   \table_row3{   <b>`Network.DNS1Address`</b>,
///                  \anchor Network_DNS1Address
///                  _string_,
///     @return The network DNS 1 address.
///     <p>
///   }
///   \table_row3{   <b>`Network.DNS2Address`</b>,
///                  \anchor Network_DNS2Address
///                  _string_,
///     @return The network DNS 2 address.
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 8> network_labels = {{
    {"isdhcp", NETWORK_IS_DHCP},
    {"ipaddress",       NETWORK_IP_ADDRESS}, //labels from here
    {"linkstate",       NETWORK_LINK_STATE},
    {"macaddress",      NETWORK_MAC_ADDRESS},
    {"subnetmask",      NETWORK_SUBNET_MASK},
    {"gatewayaddress",  NETWORK_GATEWAY_ADDRESS},
    {"dns1address",     NETWORK_DNS1_ADDRESS},
    {"dns2address",     NETWORK_DNS2_ADDRESS},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_musicpartymode Music party mode
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`MusicPartyMode.Enabled`</b>,
///                  \anchor MusicPartyMode_Enabled
///                  _boolean_,
///     @return **True** if Party Mode is enabled.
///     <p>
///   }
///   \table_row3{   <b>`MusicPartyMode.SongsPlayed`</b>,
///                  \anchor MusicPartyMode_SongsPlayed
///                  _string_,
///     @return The number of songs played during Party Mode.
///     <p>
///   }
///   \table_row3{   <b>`MusicPartyMode.MatchingSongs`</b>,
///                  \anchor MusicPartyMode_MatchingSongs
///                  _string_,
///     @return The number of songs available to Party Mode.
///     <p>
///   }
///   \table_row3{   <b>`MusicPartyMode.MatchingSongsPicked`</b>,
///                  \anchor MusicPartyMode_MatchingSongsPicked
///                  _string_,
///     @return The number of songs picked already for Party Mode.
///     <p>
///   }
///   \table_row3{   <b>`MusicPartyMode.MatchingSongsLeft`</b>,
///                  \anchor MusicPartyMode_MatchingSongsLeft
///                  _string_,
///     @return The number of songs left to be picked from for Party Mode.
///     <p>
///   }
///   \table_row3{   <b>`MusicPartyMode.RelaxedSongsPicked`</b>,
///                  \anchor MusicPartyMode_RelaxedSongsPicked
///                  _string_,
///     @todo Not currently used
///     <p>
///   }
///   \table_row3{   <b>`MusicPartyMode.RandomSongsPicked`</b>,
///                  \anchor MusicPartyMode_RandomSongsPicked
///                  _string_,
///     @return The number of unique random songs picked during Party Mode.
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 7> musicpartymode = {{
    {"enabled",             MUSICPM_ENABLED},
    {"songsplayed",         MUSICPM_SONGSPLAYED},
    {"matchingsongs",       MUSICPM_MATCHINGSONGS},
    {"matchingsongspicked", MUSICPM_MATCHINGSONGSPICKED},
    {"matchingsongsleft",   MUSICPM_MATCHINGSONGSLEFT},
    {"relaxedsongspicked",  MUSICPM_RELAXEDSONGSPICKED},
    {"randomsongspicked",   MUSICPM_RANDOMSONGSPICKED},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_MusicPlayer Music player
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`MusicPlayer.Offset(number).Exists`</b>,
///                  \anchor MusicPlayer_Offset
///                  _boolean_,
///     @return **True** if the music players playlist has a song queued in
///     position (number).
///     @param number - song position
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Title`</b>,
///                  \anchor MusicPlayer_Title
///                  _string_,
///     @return The title of the currently playing song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.offset(number).Title`</b>,
///                  \anchor MusicPlayer_Offset_Title
///                  _string_,
///     @return The title of the song which has an offset `number` with respect to the
///     current playing song.
///     @param number - the offset number with respect to the current playing song
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Position(number).Title`</b>,
///                  \anchor MusicPlayer_Position_Title
///                  _string_,
///     @return The title of the song which as an offset `number` with respect to the
///     start of the playlist.
///     @param number - the offset number with respect to the start of the playlist
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Album`</b>,
///                  \anchor MusicPlayer_Album
///                  _string_,
///     @return The album from which the current song is from.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.offset(number).Album`</b>,
///                  \anchor MusicPlayer_OffSet_Album
///                  _string_,
///     @return The album from which the song with offset `number` with respect to
///     the current song is from.
///     @param number - the offset number with respect to the current playing song
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Position(number).Album`</b>,
///                  \anchor MusicPlayer_Position_Album
///                  _string_,
///     @return The album from which the song with offset `number` with respect to
///     the start of the playlist is from.
///     @param number - the offset number with respect to the start of the playlist
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Role.Composer)`</b>,
///                  \anchor MusicPlayer_Property_Role_Composer
///                  _string_,
///     @return The name of the person who composed the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Composer `MusicPlayer.Property(Role.Composer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Role.Conductor)`</b>,
///                  \anchor MusicPlayer_Property_Role_Conductor
///                  _string_,
///     @return The name of the person who conducted the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Conductor `MusicPlayer.Property(Role.Conductor)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Role.Orchestra)`</b>,
///                  \anchor MusicPlayer_Property_Role_Orchestra
///                  _string_,
///     @return The name of the orchestra performing the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Orchestra `MusicPlayer.Property(Role.Orchestra)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Role.Lyricist)`</b>,
///                  \anchor MusicPlayer_Property_Role_Lyricist
///                  _string_,
///     @return The name of the person who wrote the lyrics of the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Lyricist `MusicPlayer.Property(Role.Lyricist)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Role.Remixer)`</b>,
///                  \anchor MusicPlayer_Property_Role_Remixer
///                  _string_,
///     @return The name of the person who remixed the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Remixer `MusicPlayer.Property(Role.Remixer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Role.Arranger)`</b>,
///                  \anchor MusicPlayer_Property_Role_Arranger
///                  _string_,
///     @return The name of the person who arranged the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Arranger `MusicPlayer.Property(Role.Arranger)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Role.Engineer)`</b>,
///                  \anchor MusicPlayer_Property_Role_Engineer
///                  _string_,
///     @return The name of the person who was the engineer of the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Engineer `MusicPlayer.Property(Role.Engineer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Role.Producer)`</b>,
///                  \anchor MusicPlayer_Property_Role_Producer
///                  _string_,
///     @return The name of the person who produced the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Producer `MusicPlayer.Property(Role.Producer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Role.DJMixer)`</b>,
///                  \anchor MusicPlayer_Property_Role_DJMixer
///                  _string_,
///     @return The name of the dj who remixed the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_DJMixer `MusicPlayer.Property(Role.DJMixer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Role.Mixer)`</b>,
///                  \anchor MusicPlayer_Property_Role_Mixer
///                  _string_,
///     @return The name of the dj who remixed the selected song.
///     @todo So maybe rather than a row each have one entry for Role.XXXXX with composer\, arranger etc. as listed values
///     @note MusicPlayer.Property(Role.any_custom_role) also works\,
///     where any_custom_role could be an instrument violin or some other production activity e.g. sound engineer.
///     The roles listed (composer\, arranger etc.) are standard ones but there are many possible.
///     Music file tagging allows for the musicians and all other people involved in the recording to be added\, Kodi
///     will gathers and stores that data\, and it is available to GUI.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Mixer `MusicPlayer.Property(Role.Mixer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Album_Mood)`</b>,
///                  \anchor MusicPlayer_Property_Album_Mood
///                  _string_,
///     @return the moods of the currently playing Album
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Album_Style)`</b>,
///                  \anchor MusicPlayer_Property_Album_Style
///                  _string_,
///     @return the styles of the currently playing Album.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Album_Theme)`</b>,
///                  \anchor MusicPlayer_Property_Album_Theme
///                  _string_,
///     @return The themes of the currently playing Album
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Album_Type)`</b>,
///                  \anchor MusicPlayer_Property_Album_Type
///                  _string_,
///     @return The album type (e.g. compilation\, enhanced\, explicit lyrics) of the
///     currently playing album.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Album_Label)`</b>,
///                  \anchor MusicPlayer_Property_Album_Label
///                  _string_,
///     @return The record label of the currently playing album.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Album_Description)`</b>,
///                  \anchor MusicPlayer_Property_Album_Description
///                  _string_,
///     @return A review of the currently playing album
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Artist`</b>,
///                  \anchor MusicPlayer_Artist
///                  _string_,
///     @return Artist(s) of current song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.offset(number).Artist`</b>,
///                  \anchor MusicPlayer_Offset_Artist
///                  _string_,
///     @return Artist(s) of the song which has an offset `number` with respect
///     to the current playing song.
///     @param number - the offset of the song with respect to the current
///     playing song
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Position(number).Artist`</b>,
///                  \anchor MusicPlayer_Position_Artist
///                  _string_,
///     @return Artist(s) of the song which has an offset `number` with respect
///     to the start of the playlist.
///     @param number - the offset of the song with respect to
///     the start of the playlist
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.AlbumArtist`</b>,
///                  \anchor MusicPlayer_AlbumArtist
///                  _string_,
///     @return The album artist of the currently playing song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Cover`</b>,
///                  \anchor MusicPlayer_Cover
///                  _string_,
///     @return The album cover of currently playing song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Sortname)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Sortname
///                  _string_,
///     @return The sortname of the currently playing Artist.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link MusicPlayer_Property_Artist_Sortname `MusicPlayer.Property(Artist_Sortname)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Type)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Type
///                  _string_,
///     @return The type of the currently playing Artist - person\,
///     group\, orchestra\, choir etc.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link MusicPlayer_Property_Artist_Type `MusicPlayer.Property(Artist_Type)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Gender)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Gender
///                  _string_,
///     @return The gender of the currently playing Artist - male\,
///     female\, other.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link MusicPlayer_Property_Artist_Gender `MusicPlayer.Property(Artist_Gender)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Disambiguation)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Disambiguation
///                  _string_,
///     @return A brief description of the currently playing Artist that differentiates them
///     from others with the same name.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link MusicPlayer_Property_Artist_Disambiguation `MusicPlayer.Property(Artist_Disambiguation)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Born)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Born
///                  _string_,
///     @return The date of Birth of the currently playing Artist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Died)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Died
///                  _string_,
///     @return The date of Death of the currently playing Artist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Formed)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Formed
///                  _string_,
///     @return The Formation date of the currently playing Artist/Band.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Disbanded)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Disbanded
///                  _string_,
///     @return The disbanding date of the currently playing Artist/Band.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_YearsActive)`</b>,
///                  \anchor MusicPlayer_Property_Artist_YearsActive
///                  _string_,
///     @return The years the currently Playing artist has been active.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Instrument)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Instrument
///                  _string_,
///     @return The instruments played by the currently playing artist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Description)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Description
///                  _string_,
///     @return A biography of the currently playing artist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Mood)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Mood
///                  _string_,
///     @return The moods of the currently playing artist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Style)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Style
///                  _string_,
///     @return The styles of the currently playing artist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(Artist_Genre)`</b>,
///                  \anchor MusicPlayer_Property_Artist_Genre
///                  _string_,
///     @return The genre of the currently playing artist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Genre`</b>,
///                  \anchor MusicPlayer_Genre
///                  _string_,
///     @return The genre(s) of current song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Genre(separator)`</b>,
///                  \anchor MusicPlayer_Genre_separator
///                  _string_,
///     @return A list of genres of current song\, separated by given separator\, or if no
///     separator was given separated by the advanced settings value \“itemseparator\” for music.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link MusicPlayer_Genre_separator `MusicPlayer.Genre(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.offset(number).Genre`</b>,
///                  \anchor MusicPlayer_OffSet_Genre
///                  _string_,
///     @return The genre(s) of the song with an offset `number` with respect
///     to the current playing song.
///     @param number - the offset song number with respect to the current playing
///     song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Position(number).Genre`</b>,
///                  \anchor MusicPlayer_Position_Genre
///                  _string_,
///     @return The genre(s) of the song with an offset `number` with respect
///     to the start of the playlist.
///     @param number - the offset song number with respect to the start of the
///     playlist
///     song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Lyrics`</b>,
///                  \anchor MusicPlayer_Lyrics
///                  _string_,
///     @return The lyrics of current song stored in ID tag info.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Year`</b>,
///                  \anchor MusicPlayer_Year
///                  _string_,
///     @return The year of release of current song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.offset(number).Year`</b>,
///                  \anchor MusicPlayer_Offset_Year
///                  _string_,
///     @return The year of release of the song with an offset `number` with
///     respect to the current playing song.
///     @param number - the offset number with respect to the current song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Position(number).Year`</b>,
///                  \anchor MusicPlayer_Position_Year
///                  _string_,
///     @return The year of release of the song with an offset `number` with
///     respect to the start of the playlist.
///     @param number - the offset number with respect to the start of the
///     playlist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Rating`</b>,
///                  \anchor MusicPlayer_Rating
///                  _string_,
///     @return The numeric Rating of current song (1-10).
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.offset(number).Rating`</b>,
///                  \anchor MusicPlayer_OffSet_Rating
///                  _string_,
///     @return The numeric Rating of song with an offset `number` with
///     respect to the current playing song.
///     @param number - the offset with respect to the current playing song
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Position(number).Rating`</b>,
///                  \anchor MusicPlayer_Position_Rating
///                  _string_,
///     @return The numeric Rating of song with an offset `number` with
///     respect to the start of the playlist.
///     @param number - the offset with respect to the start of the playlist
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.RatingAndVotes`</b>,
///                  \anchor MusicPlayer_RatingAndVotes
///                  _string_,
///     @return The scraped rating and votes of currently playing song\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.UserRating`</b>,
///                  \anchor MusicPlayer_UserRating
///                  _string_,
///     @return The scraped rating of the currently playing song (1-10).
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_UserRating `MusicPlayer.UserRating`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Votes`</b>,
///                  \anchor MusicPlayer_Votes
///                  _string_,
///     @return The scraped votes of currently playing song\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.DiscNumber`</b>,
///                  \anchor MusicPlayer_DiscNumber
///                  _string_,
///     @return The Disc Number of current song stored in ID tag info.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.offset(number).DiscNumber`</b>,
///                  \anchor MusicPlayer_Offset_DiscNumber
///                  _string_,
///     @return The Disc Number of current song stored in ID tag info for the
///     song with an offset `number` with respect to the playing song.
///     @param number - The offset value for the song with respect to the
///     playing song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Position(number).DiscNumber`</b>,
///                  \anchor MusicPlayer_Position_DiscNumber
///                  _string_,
///     @return The Disc Number of current song stored in ID tag info for the
///     song with an offset `number` with respect to the start of the playlist.
///     @param number - The offset value for the song with respect to the
///     start of the playlist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Comment`</b>,
///                  \anchor MusicPlayer_Comment
///                  _string_,
///     @return The Comment of current song stored in ID tag info.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.offset(number).Comment`</b>,
///                  \anchor MusicPlayer_Offset_Comment
///                  _string_,
///     @return The Comment of current song stored in ID tag info for the
///     song with an offset `number` with respect to the playing song.
///     @param number - The offset value for the song with respect to the
///     playing song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Position(number).Comment`</b>,
///                  \anchor MusicPlayer_Position_Comment
///                  _string_,
///     @return The Comment of current song stored in ID tag info for the
///     song with an offset `number` with respect to the start of the playlist.
///     @param number - The offset value for the song with respect to the
///     start of the playlist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Contributors`</b>,
///                  \anchor MusicPlayer_Contributors
///                  _string_,
///     @return The list of all people who've contributed to the currently playing song
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Contributors `MusicPlayer.Contributors`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.ContributorAndRole`</b>,
///                  \anchor MusicPlayer_ContributorAndRole
///                  _string_,
///     @return The list of all people and their role who've contributed to the currently playing song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_ContributorAndRole `MusicPlayer.ContributorAndRole`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Mood`</b>,
///                  \anchor MusicPlayer_Mood
///                  _string_,
///     @return The mood of the currently playing song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_Mood `MusicPlayer.Mood`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.PlaylistPlaying`</b>,
///                  \anchor MusicPlayer_PlaylistPlaying
///                  _boolean_,
///     @return **True** if a playlist is currently playing.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Exists(relative\,position)`</b>,
///                  \anchor MusicPlayer_Exists
///                  _boolean_,
///     @return **True** if the currently playing playlist has a song queued at the given position.
///     @param relative - bool - If the position is relative
///     @param position - int - The position of the song
///     @note It is possible to define whether the position is relative or not\, default is false.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.HasPrevious`</b>,
///                  \anchor MusicPlayer_HasPrevious
///                  _boolean_,
///     @return **True** if the music player has a a Previous Song in the Playlist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.HasNext`</b>,
///                  \anchor MusicPlayer_HasNext
///                  _boolean_,
///     @return **True** if the music player has a next song queued in the Playlist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.PlayCount`</b>,
///                  \anchor MusicPlayer_PlayCount
///                  _integer_,
///     @return The play count of currently playing song\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.LastPlayed`</b>,
///                  \anchor MusicPlayer_LastPlayed
///                  _string_,
///     @return The last play date of currently playing song\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.TrackNumber`</b>,
///                  \anchor MusicPlayer_TrackNumber
///                  _string_,
///     @return The track number of current song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.offset(number).TrackNumber`</b>,
///                  \anchor MusicPlayer_Offset_TrackNumber
///                  _string_,
///     @return The track number of the song with an offset `number`
///     with respect to the current playing song.
///     @param number - The offset number of the song with respect to the
///     playing song
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Position(number).TrackNumber`</b>,
///                  \anchor MusicPlayer_Position_TrackNumber
///                  _string_,
///     @return The track number of the song with an offset `number`
///     with respect to start of the playlist.
///     @param number - The offset number of the song with respect
///     to start of the playlist
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Duration`</b>,
///                  \anchor MusicPlayer_Duration
///                  _string_,
///     @return The duration of the current song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.offset(number).Duration`</b>,
///                  \anchor MusicPlayer_Offset_Duration
///                  _string_,
///     @return The duration of the song with an offset `number`
///     with respect to the current playing song.
///     @param number - the offset number of the song with respect
///     to the current playing song
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Position(number).Duration`</b>,
///                  \anchor MusicPlayer_Position_Duration
///                  _string_,
///     @return The duration of the song with an offset `number`
///     with respect to the start of the playlist.
///     @param number - the offset number of the song with respect
///     to the start of the playlist
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.BitRate`</b>,
///                  \anchor MusicPlayer_BitRate
///                  _string_,
///     @return The bitrate of current song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Channels(format)`</b>,
///                  \anchor MusicPlayer_Channels
///                  _string_,
///     @param[in] format (optional) format of the infolabel.
///     (possible values: see \ref ListItem_AudioChannels "ListItem.AudioChannels").
///     @return The channel information of the current song\, formatted in the optional format.
///     (possible values: see \ref ListItem_AudioChannels "ListItem.AudioChannels").
///     <p><hr>
///     @skinning_v22 **[Infolabel Updated]** \link MusicPlayer_Channels `MusicPlayer.Channels`\endlink
///     added optional format parameter
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.BitsPerSample`</b>,
///                  \anchor MusicPlayer_BitsPerSample
///                  _string_,
///     @return The number of bits per sample of current song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.SampleRate`</b>,
///                  \anchor MusicPlayer_SampleRate
///                  _string_,
///     @return The samplerate of current playing song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Codec`</b>,
///                  \anchor MusicPlayer_Codec
///                  _string_,
///     @return The codec of current playing song.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.PlaylistPosition`</b>,
///                  \anchor MusicPlayer_PlaylistPosition
///                  _string_,
///     @return The position of the current song in the current music playlist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.PlaylistLength`</b>,
///                  \anchor MusicPlayer_PlaylistLength
///                  _string_,
///     @return The total size of the current music playlist.
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.ChannelName`</b>,
///                  \anchor MusicPlayer_ChannelName
///                  _string_,
///     @return The channel name of the radio programme that's currently playing (PVR).
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.ChannelLogo`</b>,
///                  \anchor MusicPlayer_ChannelLogo
///                  _string_,
///     @return The path for the logo of the currently playing radio channel\, if available (PVR).
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link MusicPlayer_ChannelLogo `MusicPlayer.ChannelLogo`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.ChannelNumberLabel`</b>,
///                  \anchor MusicPlayer_ChannelNumberLabel
///                  _string_,
///     @return The channel and subchannel number of the radio channel that's currently
///     playing (PVR).
///     <p><hr>
///     @skinning_v14 **[New Infolabel]** \link MusicPlayer_ChannelNumberLabel `MusicPlayer.ChannelNumberLabel`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.ChannelGroup`</b>,
///                  \anchor MusicPlayer_ChannelGroup
///                  _string_,
///     @return The channel group of the radio programme that's currently playing (PVR).
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Property(propname)`</b>,
///                  \anchor MusicPlayer_Property_Propname
///                  _string_,
///     @return The requested property value of the currently playing item.
///     @param propname - The requested property
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.DBID`</b>,
///                  \anchor MusicPlayer_DBID
///                  _string_,
///     @return The database id of the currently playing song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link MusicPlayer_DBID `MusicPlayer.DBID`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.DiscTitle`</b>,
///                  \anchor MusicPlayer_DiscTitle
///                  _string_,
///     @return The title of the disc currently playing.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link MusicPlayer_DiscTitle `MusicPlayer.DiscTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.ReleaseDate`</b>,
///                  \anchor MusicPlayer_ReleaseDate
///                  _string_,
///     @return The release date of the song currently playing.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link MusicPlayer_ReleaseDate `MusicPlayer.ReleaseDate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.OriginalDate`</b>,
///                  \anchor MusicPlayer_OriginalDate
///                  _string_,
///     @return The original release date of the song currently playing.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link MusicPlayer_OriginalDate `MusicPlayer.OriginalDate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.BPM`</b>,
///                  \anchor MusicPlayer_BPM
///                  _string_,
///     @return The bpm of the track currently playing.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link MusicPlayer_BPM `MusicPlayer.BPM`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.IsMultiDisc`</b>,
///                  \anchor MusicPlayer_IsMultiDisc
///                  _boolean_,
///     @return Returns **true** if the album currently playing has more than one disc.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link MusicPlayer_IsMultiDisc `MusicPlayer.IsMultiDisc`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.TotalDiscs`</b>,
///                  \anchor MusicPlayer_TotalDiscs
///                  _string_,
///     @return The number of discs associated with the currently playing album.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link MusicPlayer_TotalDiscs `MusicPlayer.TotalDiscs`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.Station`</b>,
///                  \anchor MusicPlayer_Station
///                  _string_,
///     @return The name of the radio station currently playing (if available).
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link MusicPlayer_Station `MusicPlayer.Station`\endlink
///     <p>
///   }
///   \table_row3{   <b>`MusicPlayer.MediaProviders`</b>,
///                  \anchor MusicPlayer_MediaProviders
///                  _string_,
///     @return string containing the names of the providers of the currently playing media\, separated by commas if multiple are present.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link MusicPlayer_MediaProviders `MusicPlayer.MediaProviders`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 46> musicplayer = {{
    {"title",               MUSICPLAYER_TITLE},
    {"album",               MUSICPLAYER_ALBUM},
    {"artist",              MUSICPLAYER_ARTIST},
    {"albumartist",         MUSICPLAYER_ALBUM_ARTIST},
    {"year",                MUSICPLAYER_YEAR},
    {"genre",               MUSICPLAYER_GENRE},
    {"duration",            MUSICPLAYER_DURATION},
    {"tracknumber",         MUSICPLAYER_TRACK_NUMBER},
    {"cover",               MUSICPLAYER_COVER},
    {"bitrate",             MUSICPLAYER_BITRATE},
    {"playlistlength",      MUSICPLAYER_PLAYLISTLEN},
    {"playlistposition",    MUSICPLAYER_PLAYLISTPOS},
    {"channels",            MUSICPLAYER_CHANNELS},
    {"bitspersample",       MUSICPLAYER_BITSPERSAMPLE},
    {"samplerate",          MUSICPLAYER_SAMPLERATE},
    {"codec",               MUSICPLAYER_CODEC},
    {"discnumber",          MUSICPLAYER_DISC_NUMBER},
    {"disctitle",           MUSICPLAYER_DISC_TITLE},
    {"rating",              MUSICPLAYER_RATING},
    {"ratingandvotes",      MUSICPLAYER_RATING_AND_VOTES},
    {"userrating",          MUSICPLAYER_USER_RATING},
    {"votes",               MUSICPLAYER_VOTES},
    {"comment",             MUSICPLAYER_COMMENT},
    {"mood",                MUSICPLAYER_MOOD},
    {"contributors",        MUSICPLAYER_CONTRIBUTORS},
    {"contributorandrole",  MUSICPLAYER_CONTRIBUTOR_AND_ROLE},
    {"lyrics",              MUSICPLAYER_LYRICS},
    {"playlistplaying",     MUSICPLAYER_PLAYLISTPLAYING},
    {"exists",              MUSICPLAYER_EXISTS},
    {"hasprevious",         MUSICPLAYER_HASPREVIOUS},
    {"hasnext",             MUSICPLAYER_HASNEXT},
    {"playcount",           MUSICPLAYER_PLAYCOUNT},
    {"lastplayed",          MUSICPLAYER_LASTPLAYED},
    {"channelname",         MUSICPLAYER_CHANNEL_NAME},
    {"channellogo",         MUSICPLAYER_CHANNEL_LOGO},
    {"channelnumberlabel",  MUSICPLAYER_CHANNEL_NUMBER},
    {"channelgroup",        MUSICPLAYER_CHANNEL_GROUP},
    {"dbid",                MUSICPLAYER_DBID},
    {"property",            MUSICPLAYER_PROPERTY},
    {"releasedate",         MUSICPLAYER_RELEASEDATE},
    {"originaldate",        MUSICPLAYER_ORIGINALDATE},
    {"bpm",                 MUSICPLAYER_BPM},
    {"ismultidisc",         MUSICPLAYER_ISMULTIDISC},
    {"totaldiscs",          MUSICPLAYER_TOTALDISCS},
    {"station",             MUSICPLAYER_STATIONNAME},
    {"mediaproviders",      MUSICPLAYER_MEDIAPROVIDERS},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Videoplayer Video player
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`VideoPlayer.UsingOverlays`</b>,
///                  \anchor VideoPlayer_UsingOverlays
///                  _boolean_,
///     @return **True** if the video player is using the hardware overlays render
///     method.
///     @note This is useful\, as with hardware overlays you have no alpha blending to
///     the video image\, so shadows etc. need redoing\, or disabling.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.IsFullscreen`</b>,
///                  \anchor VideoPlayer_IsFullscreen
///                  _boolean_,
///     @return **True** if the video player is in fullscreen mode.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.HasMenu`</b>,
///                  \anchor VideoPlayer_HasMenu
///                  _boolean_,
///     @return **True** if the video player has a menu (ie is playing a DVD).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.HasInfo`</b>,
///                  \anchor VideoPlayer_HasInfo
///                  _boolean_,
///     @return **True** if the current playing video has information from the
///     library or from a plugin (eg director/plot etc.)
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.HasVideoVersions`</b>,
///                  \anchor VideoPlayer_HasVideoVersions
///                  _boolean_,
///     @return **True** when the played item has multiple video versions.
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link VideoPlayer_HasVideoVersions `VideoPlayer.HasVideoVersions`\endlink
///   }
///   \table_row3{   <b>`VideoPlayer.Content(parameter)`</b>,
///                  \anchor VideoPlayer_Content
///                  _boolean_,
///     @return **True** if the current Video you are playing is contained in
///     corresponding Video Library sections. The following values are accepted:
///     - <b>files</b>
///     - <b>movies</b>
///     - <b>episodes</b>
///     - <b>musicvideos</b>
///     - <b>livetv</b>
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.HasSubtitles`</b>,
///                  \anchor VideoPlayer_HasSubtitles
///                  _boolean_,
///     @return **True** if there are subtitles available for video.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.HasTeletext`</b>,
///                  \anchor VideoPlayer_HasTeletext
///                  _boolean_,
///     @return **True** if teletext is usable on played TV channel.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.IsStereoscopic`</b>,
///                  \anchor VideoPlayer_IsStereoscopic
///                  _boolean_,
///     @return **True** when the currently playing video is a 3D (stereoscopic)
///     video.
///     <p><hr>
///     @skinning_v13 **[New Boolean Condition]** \link VideoPlayer_IsStereoscopic `VideoPlayer.IsStereoscopic`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.SubtitlesEnabled`</b>,
///                  \anchor VideoPlayer_SubtitlesEnabled
///                  _boolean_,
///     @return **True** if subtitles are turned on for video.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.HasEpg`</b>,
///                  \anchor VideoPlayer_HasEpg
///                  _boolean_,
///     @return **True** if epg information is available for the currently playing
///     programme (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.CanResumeLiveTV`</b>,
///                  \anchor VideoPlayer_CanResumeLiveTV
///                  _boolean_,
///     @return **True** if a in-progress PVR recording is playing an the respective
///     live TV channel is available.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Title`</b>,
///                  \anchor VideoPlayer_Title
///                  _string_,
///     @return The title of currently playing video.
///     @note If it's in the database it will return the database title\, else the filename.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Title`</b>,
///                  \anchor VideoPlayer_Offset_Title
///                  _string_,
///     @return The title of video which has an offset `number` with respect to the currently playing video.
///     @note If it's in the database it will return the database title\, else the filename.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Title `VideoPlayer.offset(number).Title`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Title`</b>,
///                  \anchor VideoPlayer_Position_Title
///                  _string_,
///     @return The title of the video which has an offset `number` with respect to the start of the playlist.
///     @note If it's in the database it will return the database title\, else the filename.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Title `VideoPlayer.position(number).Title`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.OriginalTitle`</b>,
///                  \anchor VideoPlayer_OriginalTitle
///                  _string_,
///     @return The original title of currently playing video. If it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).OriginalTitle`</b>,
///                  \anchor VideoPlayer_Offset_OriginalTitle
///                  _string_,
///     @return The original title of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_OriginalTitle `VideoPlayer.offset(number).OriginalTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).OriginalTitle`</b>,
///                  \anchor VideoPlayer_Position_OriginalTitle
///                  _string_,
///     @return The original title of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_OriginalTitle `VideoPlayer.position(number).OriginalTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.TVShowTitle`</b>,
///                  \anchor VideoPlayer_TVShowTitle
///                  _string_,
///     @return The title of currently playing episode's tvshow name.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).TVShowTitle`</b>,
///                  \anchor VideoPlayer_Offset_TVShowTitle
///                  _string_,
///     @return The title of the episode's tvshow name which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_TVShowTitle `VideoPlayer.offset(number).TVShowTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).TVShowTitle`</b>,
///                  \anchor VideoPlayer_Position_TVShowTitle
///                  _string_,
///     @return The title of the episode's tvshow name which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_TVShowTitle `VideoPlayer.position(number).TVShowTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Season`</b>,
///                  \anchor VideoPlayer_Season
///                  _string_,
///     @return The season number of the currently playing episode\, if it's in the database.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link VideoPlayer_Season `VideoPlayer.Season`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Season`</b>,
///                  \anchor VideoPlayer_Offset_Season
///                  _string_,
///     @return The season number of the episode which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Season `VideoPlayer.offset(number).Season`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Season`</b>,
///                  \anchor VideoPlayer_Position_Season
///                  _string_,
///     @return The season number of the episode which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Season `VideoPlayer.position(number).Season`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Episode`</b>,
///                  \anchor VideoPlayer_Episode
///                  _string_,
///     @return The episode number of the currently playing episode.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link VideoPlayer_Episode `VideoPlayer.Episode`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Episode`</b>,
///                  \anchor VideoPlayer_Offset_Episode
///                  _string_,
///     @return The episode number of the episode which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Episode `VideoPlayer.offset(number).Episode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Episode`</b>,
///                  \anchor VideoPlayer_Position_Episode
///                  _string_,
///     @return The episode number of the episode which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Episode `VideoPlayer.position(number).Episode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Genre`</b>,
///                  \anchor VideoPlayer_Genre
///                  _string_,
///     @return The genre(s) of current movie\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Genre(separator)`</b>,
///                  \anchor VideoPlayer_Genre_separator
///                  _string_,
///     @return A list of genres of current movie\, separated by given separator\, or if no
///     separator was given separated by the advanced settings value \“itemseparator\” for videos.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_Genre_separator `VideoPlayer.Genre(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Genre`</b>,
///                  \anchor VideoPlayer_Offset_Genre
///                  _string_,
///     @return The genre(s) of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Genre `VideoPlayer.offset(number).Genre`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Genre`</b>,
///                  \anchor VideoPlayer_Position_Genre
///                  _string_,
///     @return The genre(s) of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Genre `VideoPlayer.position(number).Genre`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Director`</b>,
///                  \anchor VideoPlayer_Director
///                  _string_,
///     @return The director of current movie\, if it's in the database.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link VideoPlayer_Director `VideoPlayer.Director`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Director(separator)`</b>,
///                  \anchor VideoPlayer_Director_separator
///                  _string_,
///     @return A list of directors of the currently playing video\, separated by given separator\,
///     or if no separator was given separated by the advanced settings value \“itemseparator\” for
///     video items.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_Director_separator `VideoPlayer.Director(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Director`</b>,
///                  \anchor VideoPlayer_Offset_Director
///                  _string_,
///     @return The director of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Director `VideoPlayer.offset(number).VideoPlayer_Offset_Director`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Director`</b>,
///                  \anchor VideoPlayer_Position_Director
///                  _string_,
///     @return The director of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Director `VideoPlayer.position(number).Director`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Country`</b>,
///                  \anchor VideoPlayer_Country
///                  _string_,
///     @return The production country of current movie\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Country`</b>,
///                  \anchor VideoPlayer_Offset_Country
///                  _string_,
///     @return The production country of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Country `VideoPlayer.offset(number).Country`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Country`</b>,
///                  \anchor VideoPlayer_Position_Country
///                  _string_,
///     @return The production country of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Country `VideoPlayer.position(number).Country`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Year`</b>,
///                  \anchor VideoPlayer_Year
///                  _string_,
///     @return The year of release of current movie\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Year`</b>,
///                  \anchor VideoPlayer_Offset_Year
///                  _string_,
///     @return The year of release of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Year `VideoPlayer.offset(number).Year`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Year`</b>,
///                  \anchor VideoPlayer_Position_Year
///                  _string_,
///     @return The year of release of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Year `VideoPlayer.position(number).Year`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Cover`</b>,
///                  \anchor VideoPlayer_Cover
///                  _string_,
///     @return The cover of currently playing movie.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Cover`</b>,
///                  \anchor VideoPlayer_Offset_Cover
///                  _string_,
///     @return The cover of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Cover `VideoPlayer.offset(number).Cover`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Cover`</b>,
///                  \anchor VideoPlayer_Position_Cover
///                  _string_,
///     @return The cover of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Cover `VideoPlayer.position(number).Cover`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Rating`</b>,
///                  \anchor VideoPlayer_Rating
///                  _string_,
///     @return The scraped rating of current movie\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Rating`</b>,
///                  \anchor VideoPlayer_Offset_Rating
///                  _string_,
///     @return The scraped rating of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Rating `VideoPlayer.offset(number).Rating`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Rating`</b>,
///                  \anchor VideoPlayer_Position_Rating
///                  _string_,
///     @return The scraped rating of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Rating `VideoPlayer.position(number).Rating`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.UserRating`</b>,
///                  \anchor VideoPlayer_UserRating
///                  _string_,
///     @return The user rating of the currently playing item.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link VideoPlayer_UserRating `VideoPlayer.UserRating`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).UserRating`</b>,
///                  \anchor VideoPlayer_Offset_UserRating
///                  _string_,
///     @return The user rating of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_UserRating `VideoPlayer.offset(number).UserRating`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).UserRating`</b>,
///                  \anchor VideoPlayer_Position_UserRating
///                  _string_,
///     @return The user rating of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_UserRating `VideoPlayer.position(number).UserRating`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Votes`</b>,
///                  \anchor VideoPlayer_Votes
///                  _string_,
///     @return The scraped votes of current movie\, if it's in the database.
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link VideoPlayer_Votes `VideoPlayer.Votes`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Votes`</b>,
///                  \anchor VideoPlayer_Offset_Votes
///                  _string_,
///     @return The scraped votes of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Votes `VideoPlayer.offset(number).Votes`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Votes`</b>,
///                  \anchor VideoPlayer_Position_Votes
///                  _string_,
///     @return The scraped votes of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Votes `VideoPlayer.position(number).Votes`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.RatingAndVotes`</b>,
///                  \anchor VideoPlayer_RatingAndVotes
///                  _string_,
///     @return The scraped rating and votes of current movie\, if it's in the database
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).RatingAndVotes`</b>,
///                  \anchor VideoPlayer_Offset_RatingAndVotes
///                  _string_,
///     @return The scraped rating and votes of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_RatingAndVotes `VideoPlayer.offset(number).RatingAndVotes`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).RatingAndVotes`</b>,
///                  \anchor VideoPlayer_Position_RatingAndVotes
///                  _string_,
///     @return The scraped rating and votes of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_RatingAndVotes `VideoPlayer.position(number).RatingAndVotes`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.mpaa`</b>,
///                  \anchor VideoPlayer_mpaa
///                  _string_,
///     @return The MPAA rating of current movie\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).mpaa`</b>,
///                  \anchor VideoPlayer_Offset_mpaa
///                  _string_,
///     @return The MPAA rating of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_mpaa `VideoPlayer.offset(number).mpaa`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).mpaa`</b>,
///                  \anchor VideoPlayer_Position_mpaa
///                  _string_,
///     @return The MPAA rating of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_mpaa `VideoPlayer.position(number).mpaa`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Art(type)`</b>,
///                  \anchor VideoPlayer_art
///                  _string_,
///     @return The art path for the requested arttype and for the currently playing video.
///     @param type - can virtually be anything\, refers to the art type keyword in the art map (poster\, fanart\, banner\, thumb\, etc)
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link VideoPlayer_art `VideoPlayer.Art(type)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Art(type)`</b>,
///                  \anchor VideoPlayer_Offset_art
///                  _string_,
///     @return The art path for the requested arttype and for the video which has an offset `number` with respect to the currently playing video.
///     @param number - the offset with respect to the start of the playlist
///     @param type - can virtually be anything\, refers to the art type keyword in the art map (poster\, fanart\, banner\, thumb\, etc)
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link VideoPlayer_Offset_mpaa `VideoPlayer.offset(number).Art(type)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Art(type)`</b>,
///                  \anchor VideoPlayer_position_art
///                  _string_,
///     @return The art path for the requested arttype and for the video which has an offset `number` with respect to the start of the playlist.
///     @param number - the offset with respect to the start of the playlist
///     @param type - can virtually be anything\, refers to the art type keyword in the art map (poster\, fanart\, banner\, thumb\, etc)
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link VideoPlayer_position_art `VideoPlayer.position(number).Art(type)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.IMDBNumber`</b>,
///                  \anchor VideoPlayer_IMDBNumber
///                  _string_,
///     @return The IMDb ID of the current movie\, if it's in the database.
///     <p><hr>
///     @skinning_v15 **[New Infolabel]** \link VideoPlayer_IMDBNumber `VideoPlayer.IMDBNumber`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).IMDBNumber`</b>,
///                  \anchor VideoPlayer_Offset_IMDBNumber
///                  _string_,
///     @return The IMDb ID of the the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_IMDBNumber `VideoPlayer.offset(number).IMDBNumber`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).IMDBNumber`</b>,
///                  \anchor VideoPlayer_Position_IMDBNumber
///                  _string_,
///     @return The IMDb ID of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_IMDBNumber `VideoPlayer.position(number).IMDBNumber`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Top250`</b>,
///                  \anchor VideoPlayer_Top250
///                  _string_,
///     @return The IMDb Top250 position of the currently playing movie\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Top250`</b>,
///                  \anchor VideoPlayer_Offset_Top250
///                  _string_,
///     @return The IMDb Top250 position of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Top250 `VideoPlayer.offset(number).Top250`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Top250`</b>,
///                  \anchor VideoPlayer_Position_Top250
///                  _string_,
///     @return The IMDb Top250 position of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Top250 `VideoPlayer.position(number).Top250`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.EpisodeName`</b>,
///                  \anchor VideoPlayer_EpisodeName
///                  _string_,
///     @return The name of the episode if the playing video is a TV Show\,
///     if it's in the database (PVR).
///     <p><hr>
///     @skinning_v15 **[New Infolabel]** \link VideoPlayer_EpisodeName `VideoPlayer.EpisodeName`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.PlaylistPosition`</b>,
///                  \anchor VideoPlayer_PlaylistPosition
///                  _string_,
///     @return The position of the current song in the current video playlist.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.PlaylistLength`</b>,
///                  \anchor VideoPlayer_PlaylistLength
///                  _string_,
///     @return The total size of the current video playlist.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Cast`</b>,
///                  \anchor VideoPlayer_Cast
///                  _string_,
///     @return A list of cast members\, separated by carriage returns.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link VideoPlayer_Cast `VideoPlayer.Cast`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Cast(separator)`</b>,
///                  \anchor VideoPlayer_Cast_separator
///                  _string_,
///     @return A list of cast members of the currently playing video\, separated by given
///     separator\, or if no separator was given separated by carriage returns.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_Cast_separator `VideoPlayer.Cast(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.CastAndRole`</b>,
///                  \anchor VideoPlayer_CastAndRole
///                  _string_,
///     @return A list of cast members and roles\, separated by carriage
///     returns. Every cast/role combination is formatted 'cast' as 'role' where 'as' is localised.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.CastAndRole(separator)`</b>,
///                  \anchor VideoPlayer_CastAndRole_separator
///                  _string_,
///     @return A list of cast members and roles of the currently playing video\, pairs separated by
///     given separator\, or if no separator was given separated by carriage returns.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_CastAndRole_separator `VideoPlayer.CastAndRole(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Album`</b>,
///                  \anchor VideoPlayer_Album
///                  _string_,
///     @return The album from which the current Music Video is from\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Album`</b>,
///                  \anchor VideoPlayer_Offset_Album
///                  _string_,
///     @return The album from which the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Album `VideoPlayer.offset(number).Album`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Album`</b>,
///                  \anchor VideoPlayer_Position_Album
///                  _string_,
///     @return The album from which the music video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Album `VideoPlayer.position(number).Album`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Artist`</b>,
///                  \anchor VideoPlayer_Artist
///                  _string_,
///     @return The artist(s) of current Music Video\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Artist`</b>,
///                  \anchor VideoPlayer_Offset_Artist
///                  _string_,
///     @return The artist(s) of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Artist `VideoPlayer.offset(number).Artist`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Artist`</b>,
///                  \anchor VideoPlayer_Position_Artist
///                  _string_,
///     @return The artist(s) of the music video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Artist `VideoPlayer.position(number).Artist`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Studio`</b>,
///                  \anchor VideoPlayer_Studio
///                  _string_,
///     @return The studio of current Music Video\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Studio`</b>,
///                  \anchor VideoPlayer_Offset_Studio
///                  _string_,
///     @return The studio of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Studio `VideoPlayer.offset(number).Studio`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Studio`</b>,
///                  \anchor VideoPlayer_Position_Studio
///                  _string_,
///     @return The studio of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Studio `VideoPlayer.position(number).Studio`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Writer`</b>,
///                  \anchor VideoPlayer_Writer
///                  _string_,
///     @return The name of Writer of current playing Video\, if it's in the database.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link VideoPlayer_Writer `VideoPlayer.Writer`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Writer(separator)`</b>,
///                  \anchor VideoPlayer_Writer_separator
///                  _string_,
///     @return A list of writers of the currently playing video\, separated by given separator\,
///     or if no separator was given separated by the advanced settings value \“itemseparator\” for
///     video items.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_Writer_separator `VideoPlayer.Writer(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Writer`</b>,
///                  \anchor VideoPlayer_Offset_Writer
///                  _string_,
///     @return The name of Writer of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Writer `VideoPlayer.offset(number).Writer`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Writer`</b>,
///                  \anchor VideoPlayer_Position_Writer
///                  _string_,
///     @return The name of Writer of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Writer `VideoPlayer.position(number).Writer`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Tagline`</b>,
///                  \anchor VideoPlayer_Tagline
///                  _string_,
///     @return The small Summary of current playing Video\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Tagline`</b>,
///                  \anchor VideoPlayer_Offset_Tagline
///                  _string_,
///     @return The small Summary of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Tagline `VideoPlayer.offset(number).Tagline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Tagline`</b>,
///                  \anchor VideoPlayer_Position_Tagline
///                  _string_,
///     @return The small Summary of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Tagline `VideoPlayer.position(number).Tagline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.PlotOutline`</b>,
///                  \anchor VideoPlayer_PlotOutline
///                  _string_,
///     @return The small Summary of current playing Video\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).PlotOutline`</b>,
///                  \anchor VideoPlayer_Offset_PlotOutline
///                  _string_,
///     @return The small Summary of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_PlotOutline `VideoPlayer.offset(number).PlotOutline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).PlotOutline`</b>,
///                  \anchor VideoPlayer_Position_PlotOutline
///                  _string_,
///     @return The small Summary of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_PlotOutline `VideoPlayer.position(number).PlotOutline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Plot`</b>,
///                  \anchor VideoPlayer_Plot
///                  _string_,
///     @return The complete Text Summary of current playing Video\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Plot`</b>,
///                  \anchor VideoPlayer_Offset_Plot
///                  _string_,
///     @return The complete Text Summary of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Plot `VideoPlayer.offset(number).Plot`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Plot`</b>,
///                  \anchor VideoPlayer_Position_Plot
///                  _string_,
///     @return The complete Text Summary of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Plot `VideoPlayer.position(number).Plot`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Premiered`</b>,
///                  \anchor VideoPlayer_Premiered
///                  _string_,
///     @return The release or aired date of the currently playing episode\, show\, movie or EPG item\,
///     if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Premiered`</b>,
///                  \anchor VideoPlayer_Offset_Premiered
///                  _string_,
///     @return The release or aired date of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Premiered `VideoPlayer.offset(number).Premiered`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Premiered`</b>,
///                  \anchor VideoPlayer_Position_Premiered
///                  _string_,
///     @return The release or aired date of the video which has an offset `number` with respect to the start of the playlist.
///     if it's in the database.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Premiered `VideoPlayer.position(number).Premiered`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.Trailer`</b>,
///                  \anchor VideoPlayer_Trailer
///                  _string_,
///     @return The path to the trailer of the currently playing movie\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).Trailer`</b>,
///                  \anchor VideoPlayer_Offset_Trailer
///                  _string_,
///     @return The path to the trailer of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_Trailer `VideoPlayer.offset(number).Title`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).Trailer`</b>,
///                  \anchor VideoPlayer_Position_Trailer
///                  _string_,
///     @return The path to the trailer of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_Trailer `VideoPlayer.position(number).Trailer`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.LastPlayed`</b>,
///                  \anchor VideoPlayer_LastPlayed
///                  _string_,
///     @return The last play date of current playing Video\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).LastPlayed`</b>,
///                  \anchor VideoPlayer_Offset_LastPlayed
///                  _string_,
///     @return The last play date of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_LastPlayed `VideoPlayer.offset(number).LastPlayed`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).LastPlayed`</b>,
///                  \anchor VideoPlayer_Position_LastPlayed
///                  _string_,
///     @return The last play date of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_LastPlayed `VideoPlayer.position(number).LastPlayed`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.PlayCount`</b>,
///                  \anchor VideoPlayer_PlayCount
///                  _string_,
///     @return The playcount of current playing Video\, if it's in the database.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).PlayCount`</b>,
///                  \anchor VideoPlayer_Offset_PlayCount
///                  _string_,
///     @return The playcount of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_PlayCount `VideoPlayer.offset(number).PlayCount`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).PlayCount`</b>,
///                  \anchor VideoPlayer_Position_PlayCount
///                  _string_,
///     @return The playcount of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_PlayCount `VideoPlayer.position(number).PlayCount`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.VideoCodec`</b>,
///                  \anchor VideoPlayer_VideoCodec
///                  _string_,
///     @return The video codec of the currently playing video (common values: see
///     \ref ListItem_VideoCodec "ListItem.VideoCodec").
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.VideoResolution`</b>,
///                  \anchor VideoPlayer_VideoResolution
///                  _string_,
///     @return The video resolution of the currently playing video (possible
///     values: see \ref ListItem_VideoResolution "ListItem.VideoResolution").
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.VideoAspect`</b>,
///                  \anchor VideoPlayer_VideoAspect
///                  _string_,
///     @return The aspect ratio of the currently playing video (possible values:
///     see \ref ListItem_VideoAspect "ListItem.VideoAspect").
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.VideoBitrate`</b>,
///                  \anchor VideoPlayer_VideoBitrate
///                  _string_,
///     @return The bitrate of the video stream of the currently playing video\, in kbps.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link VideoPlayer_VideoBitrate `VideoPlayer.VideoBitrate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.AudioCodec`</b>,
///                  \anchor VideoPlayer_AudioCodec
///                  _string_,
///     @return The audio codec of the currently playing video\, optionally 'n'
///     defines the number of the audiostream (common values: see
///     \ref ListItem_AudioCodec "ListItem.AudioCodec").
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.AudioChannels(format)`</b>,
///                  \anchor VideoPlayer_AudioChannels
///                  _string_,
///     @param[in] format (optional) format of the infolabel.
///     (possible values: see \ref ListItem_AudioChannels "ListItem.AudioChannels").
///     @return The audio channel information of the currently playing video\, formatted in the optional format
///     (possible values: see \ref ListItem_AudioChannels "ListItem.AudioChannels").
///     <p><hr>
///     @skinning_v16 **[Infolabel Updated]** \link VideoPlayer_AudioChannels `VideoPlayer.AudioChannels`\endlink
///     if a video contains no audio\, these infolabels will now return empty.
///     (they used to return 0)
///
///     @skinning_v22 **[Infolabel Updated]** \link VideoPlayer_AudioChannels `VideoPlayer.AudioChannels`\endlink
///     added optional format parameter
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.AudioBitrate`</b>,
///                  \anchor VideoPlayer_AudioBitrate
///                  _string_,
///     @return The bitrate of the audio stream of the currently playing video\, in kbps.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link VideoPlayer_AudioBitrate `VideoPlayer.AudioBitrate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.AudioLanguage`</b>,
///                  \anchor VideoPlayer_AudioLanguage
///                  _string_,
///     @return The language of the audio of the currently playing video(possible
///     values: see \ref ListItem_AudioLanguage "ListItem.AudioLanguage").
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link VideoPlayer_AudioLanguage `VideoPlayer.AudioLanguage`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.AudioLanguageEx`</b>,
///                  \anchor VideoPlayer_AudioLanguageEx
///                  _string_,
///     @return The English name of the language of the current audio stream of the currently playing item.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_AudioLanguageEx `VideoPlayer.AudioLanguageEx`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.AudioName`</b>,
///                  \anchor VideoPlayer_AudioName
///                  _string_,
///     @return The name of the active audio stream of the currently playing video.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_AudioName `VideoPlayer.AudioName`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.SubtitlesLanguage`</b>,
///                  \anchor VideoPlayer_SubtitlesLanguage
///                  _string_,
///     @return The language of the subtitle of the currently playing video
///     (possible values: see \ref ListItem_SubtitleLanguage "ListItem.SubtitleLanguage").
///     @note `VideoPlayer.SubtitlesLanguage` holds the language of the next available
///     subtitle stream if subtitles are disabled in the player
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link VideoPlayer_SubtitlesLanguage `VideoPlayer.SubtitlesLanguage`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.SubtitleLanguageEx`</b>,
///                  \anchor VideoPlayer_SubtitleLanguageEx
///                  _string_,
///     @return The English name of the language of the current subtitle stream of the currently playing item.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_SubtitleLanguageEx `VideoPlayer.SubtitleLanguageEx`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.SubtitleCodec`</b>,
///                  \anchor VideoPlayer_SubtitleCodec
///                  _string_,
///     @return The codec of the current subtitles of the currently playing video. Possible values include:
///       - <b>ass</b>
///       - <b>dvb_subtitle</b>
///       - <b>dvb_teletext</b>
///       - <b>dvd_subtitle</b>
///       - <b>hdmv_pgs_subtitle</b>
///       - <b>microdvd</b>
///       - <b>mov_text</b>
///       - <b>mpl2</b>
///       - <b>realtext</b>
///       - <b>sami</b>
///       - <b>srt</b>
///       - <b>ssa</b>
///       - <b>subrip</b>
///       - <b>text</b>
///       - <b>ttml</b>
///       - <b>vplayer</b>
///       - <b>webvtt</b>
///       - <b>xsub</b>
///
///     @note `VideoPlayer.SubtitleCodec` holds the codec of the next available subtitles stream
///     if subtitles are disabled in the player.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_SubtitleCodec `VideoPlayer.SubtitleCodec`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.SubtitleName`</b>,
///                  \anchor VideoPlayer_SubtitleName
///                  _string_,
///     @return The name of the active subtitle stream of the currently playing video.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_SubtitleName `VideoPlayer.SubtitleName`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.StereoscopicMode`</b>,
///                  \anchor VideoPlayer_StereoscopicMode
///                  _string_,
///     @return The stereoscopic mode of the currently playing video (possible
///     values: see \ref ListItem_StereoscopicMode "ListItem.StereoscopicMode").
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link VideoPlayer_StereoscopicMode `VideoPlayer.StereoscopicMode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.StartTime`</b>,
///                  \anchor VideoPlayer_StartTime
///                  _string_,
///     @return The start date and time of the currently playing epg event or recording (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.EndTime`</b>,
///                  \anchor VideoPlayer_EndTime
///                  _string_,
///     @return The end date and time of the currently playing epg event or recording (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.NextTitle`</b>,
///                  \anchor VideoPlayer_NextTitle
///                  _string_,
///     @return The title of the programme that will be played next (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.NextGenre`</b>,
///                  \anchor VideoPlayer_NextGenre
///                  _string_,
///     @return The genre of the programme that will be played next (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.NextGenre(separator)`</b>,
///                  \anchor VideoPlayer_NextGenre_separator
///                  _string_,
///     @return A list of genres of the programme that will be played next (PVR)\, separated by
///     given separator\, or if no separator was given separated by the advanced settings value
///     \“itemseparator\” for videos.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_NextGenre_separator `VideoPlayer.NextGenre(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.NextPlot`</b>,
///                  \anchor VideoPlayer_NextPlot
///                  _string_,
///     @return The plot of the programme that will be played next (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.NextPlotOutline`</b>,
///                  \anchor VideoPlayer_NextPlotOutline
///                  _string_,
///     @return The plot outline of the programme that will be played next (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.NextStartTime`</b>,
///                  \anchor VideoPlayer_NextStartTime
///                  _string_,
///     @return The start time of the programme that will be played next (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.NextEndTime`</b>,
///                  \anchor VideoPlayer_NextEndTime
///                  _string_,
///     @return The end time of the programme that will be played next (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.NextDuration`</b>,
///                  \anchor VideoPlayer_NextDuration
///                  _string_,
///     @return The duration of the programme that will be played next (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.ChannelName`</b>,
///                  \anchor VideoPlayer_ChannelName
///                  _string_,
///     @return The name of the currently tuned channel (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.ChannelLogo`</b>,
///                  \anchor VideoPlayer_ChannelLogo
///                  _string_,
///     @return The path for the logo of the currently playing TV channel\, if available (PVR).
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_ChannelLogo `VideoPlayer.ChannelLogo`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.ChannelNumberLabel`</b>,
///                  \anchor VideoPlayer_ChannelNumberLabel
///                  _string_,
///     @return The channel and subchannel number of the tv channel that's currently playing (PVR).
///     <p><hr>
///     @skinning_v14 **[New Infolabel]** \link VideoPlayer_ChannelNumberLabel `VideoPlayer.ChannelNumberLabel`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.ChannelGroup`</b>,
///                  \anchor VideoPlayer_ChannelGroup
///                  _string_,
///     @return The group of the currently tuned channel (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.ParentalRating`</b>,
///                  \anchor VideoPlayer_ParentalRating
///                  _string_,
///     @return The parental rating of the currently playing programme (PVR).
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.ParentalRatingCode`</b>,
///                  \anchor VideoPlayer_ParentalRatingCode
///                  _string_,
///     @return The parental rating code (eg: 'PG'\, etc) of the currently playing programme (PVR).
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_ParentalRatingCode `VideoPlayer.ParentalRatingCode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.ParentalRatingIcon`</b>,
///                  \anchor VideoPlayer_ParentalRatingIcon
///                  _string_,
///     @return The parental rating icon path of the currently playing programme (PVR).
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_ParentalRatingIcon `VideoPlayer.ParentalRatingIcon`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.ParentalRatingSource`</b>,
///                  \anchor VideoPlayer_ParentalRatingSource
///                  _string_,
///     @return The source used to determine the parental rating of the currently playing programme (PVR).
///     Values could include the Country alpha-3 code or the name/abbreviation
///     of the authority issuing the rating code.  Can be used with
///     the \link VideoPlayer_ParentalRatingCode `ParentalRatingCode`\endlink for skin-derived icons if required.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_ParentalRatingSource `VideoPlayer.ParentalRatingSource`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.DBID`</b>,
///                  \anchor VideoPlayer_DBID
///                  _string_,
///     @return The database id of the currently playing video
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link VideoPlayer_DBID `VideoPlayer.DBID`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.offset(number).DBID`</b>,
///                  \anchor VideoPlayer_Offset_DBID
///                  _string_,
///     @return The database id of the video which has an offset `number` with respect to the currently playing video.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Offset_DBID `VideoPlayer.offset(number).DBID`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.position(number).DBID`</b>,
///                  \anchor VideoPlayer_Position_DBID
///                  _string_,
///     @return The database id of the video which has an offset `number` with respect to the start of the playlist.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_Position_DBID `VideoPlayer.position(number).DBID`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.UniqueID(name)`</b>,
///                  \anchor VideoPlayer_UniqueID
///                  _string_,
///     @return The scraped metadata id of current movie\, if it's in the database.
///     @param name - the name of the metadata provider.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_UniqueID `VideoPlayer.UniqueID(name)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.TvShowDBID`</b>,
///                  \anchor VideoPlayer_TvShowDBID
///                  _string_,
///     @return The database id of the TvShow for the currently playing Episode
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link VideoPlayer_TvShowDBID `VideoPlayer.TvShowDBID`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.AudioStreamCount`</b>,
///                  \anchor VideoPlayer_AudioStreamCount
///                  _integer_,
///     @return The number of audio streams of the currently playing video.
///     @note If the video contains no audio streams it returns 0.
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link VideoPlayer_AudioStreamCount `VideoPlayer.AudioStreamCount`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.VideoStreamCount`</b>,
///                  \anchor VideoPlayer_VideoStreamCount
///                  _integer_,
///     @return The number of video streams of the currently playing video.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_VideoStreamCount `VideoPlayer.VideoStreamCount`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.HdrType`</b>,
///                  \anchor VideoPlayer_HdrType
///                  _string_,
///     @return String containing the name of the detected HDR type or empty if not HDR. See \ref StreamHdrType for the list of possible values.
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link VideoPlayer_HdrType `VideoPlayer.HdrType`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.HdrDetail`</b>,
///                  \anchor VideoPlayer_HdrDetail
///                  _string_,
///     @return String containing details for the HDR type (currently only for DV - profile and EL type) or empty if not HDR. Prints eg 5\, 7FEL\,
///     and compatibility ID for profile 8 eg 8.4.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_HdrDetail `VideoPlayer.HdrDetail`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.VideoVersionName`</b>,
///                  \anchor VideoPlayer_VideoVersionName
///                  _string_,
///     @return String containing the version name of the currently playing video (movie) - empty if not a movie\, version name is not set or not a version
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link VideoPlayer_VideoVersionName `VideoPlayer.VideoVersionName`\endlink
///   }
///   \table_row3{   <b>`VideoPlayer.EpisodePart`</b>,
///                  \anchor VideoPlayer_EpisodePart
///                  _string_,
///     @return string containing the number of parts of a single episode - empty if no data provided
///     <p><hr>
///     @skinning_v22 **[Infolabel Updated]** \link VideoPlayer_EpisodePart `VideoPlayer.EpisodePart`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.MediaProviders`</b>,
///                  \anchor VideoPlayer_MediaProviders
///                  _string_,
///     @return string containing the names of the providers of the currently playing media\, separated by commas if multiple are present.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_MediaProviders `VideoPlayer.MediaProviders`\endlink
///     <p>
///   }
///   \table_row3{   <b>`VideoPlayer.TitleExtraInfo`</b>,
///                  \anchor VideoPlayer_TitleExtraInfo
///                  _string_,
///     @return string containing extra information\, enriching the title of the currently playing media\, if any.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link VideoPlayer_TitleExtraInfo `VideoPlayer.TitleExtraInfo`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 88> videoplayer = {{
    {"title",                 VIDEOPLAYER_TITLE},
    {"genre",                 VIDEOPLAYER_GENRE},
    {"country",               VIDEOPLAYER_COUNTRY},
    {"originaltitle",         VIDEOPLAYER_ORIGINALTITLE},
    {"director",              VIDEOPLAYER_DIRECTOR},
    {"year",                  VIDEOPLAYER_YEAR},
    {"cover",                 VIDEOPLAYER_COVER},
    {"usingoverlays",         VIDEOPLAYER_USING_OVERLAYS},
    {"isfullscreen",          VIDEOPLAYER_ISFULLSCREEN},
    {"hasmenu",               VIDEOPLAYER_HASMENU},
    {"playlistlength",        VIDEOPLAYER_PLAYLISTLEN},
    {"playlistposition",      VIDEOPLAYER_PLAYLISTPOS},
    {"plot",                  VIDEOPLAYER_PLOT},
    {"plotoutline",           VIDEOPLAYER_PLOT_OUTLINE},
    {"episode",               VIDEOPLAYER_EPISODE},
    {"season",                VIDEOPLAYER_SEASON},
    {"rating",                VIDEOPLAYER_RATING},
    {"ratingandvotes",        VIDEOPLAYER_RATING_AND_VOTES},
    {"userrating",            VIDEOPLAYER_USER_RATING},
    {"votes",                 VIDEOPLAYER_VOTES},
    {"tvshowtitle",           VIDEOPLAYER_TVSHOW},
    {"premiered",             VIDEOPLAYER_PREMIERED},
    {"studio",                VIDEOPLAYER_STUDIO},
    {"mpaa",                  VIDEOPLAYER_MPAA},
    {"top250",                VIDEOPLAYER_TOP250},
    {"cast",                  VIDEOPLAYER_CAST},
    {"castandrole",           VIDEOPLAYER_CAST_AND_ROLE},
    {"artist",                VIDEOPLAYER_ARTIST},
    {"album",                 VIDEOPLAYER_ALBUM},
    {"writer",                VIDEOPLAYER_WRITER},
    {"tagline",               VIDEOPLAYER_TAGLINE},
    {"hasinfo",               VIDEOPLAYER_HAS_INFO},
    {"trailer",               VIDEOPLAYER_TRAILER},
    {"videocodec",            VIDEOPLAYER_VIDEO_CODEC},
    {"videoresolution",       VIDEOPLAYER_VIDEO_RESOLUTION},
    {"videoaspect",           VIDEOPLAYER_VIDEO_ASPECT},
    {"videobitrate",          VIDEOPLAYER_VIDEO_BITRATE},
    {"audiocodec",            VIDEOPLAYER_AUDIO_CODEC},
    {"audiochannels",         VIDEOPLAYER_AUDIO_CHANNELS},
    {"audiobitrate",          VIDEOPLAYER_AUDIO_BITRATE},
    {"audiolanguage",         VIDEOPLAYER_AUDIO_LANG},
    {"audiolanguageex",       VIDEOPLAYER_AUDIO_LANG_EX},
	{"audioname",             VIDEOPLAYER_AUDIO_NAME},
    {"hasteletext",           VIDEOPLAYER_HASTELETEXT},
    {"lastplayed",            VIDEOPLAYER_LASTPLAYED},
    {"playcount",             VIDEOPLAYER_PLAYCOUNT},
    {"hassubtitles",          VIDEOPLAYER_HASSUBTITLES},
    {"subtitlesenabled",      VIDEOPLAYER_SUBTITLESENABLED},
    {"subtitleslanguage",     VIDEOPLAYER_SUBTITLES_LANG},
    {"subtitlelanguageex",    VIDEOPLAYER_SUBTITLE_LANG_EX},
    {"subtitlecodec",         VIDEOPLAYER_SUBTITLE_CODEC},
    {"subtitlename",          VIDEOPLAYER_SUBTITLE_NAME},
    {"starttime",             VIDEOPLAYER_STARTTIME},
    {"endtime",               VIDEOPLAYER_ENDTIME},
    {"nexttitle",             VIDEOPLAYER_NEXT_TITLE},
    {"nextgenre",             VIDEOPLAYER_NEXT_GENRE},
    {"nextplot",              VIDEOPLAYER_NEXT_PLOT},
    {"nextplotoutline",       VIDEOPLAYER_NEXT_PLOT_OUTLINE},
    {"nextstarttime",         VIDEOPLAYER_NEXT_STARTTIME},
    {"nextendtime",           VIDEOPLAYER_NEXT_ENDTIME},
    {"nextduration",          VIDEOPLAYER_NEXT_DURATION},
    {"channelname",           VIDEOPLAYER_CHANNEL_NAME},
    {"channellogo",           VIDEOPLAYER_CHANNEL_LOGO},
    {"channelnumberlabel",    VIDEOPLAYER_CHANNEL_NUMBER},
    {"channelgroup",          VIDEOPLAYER_CHANNEL_GROUP},
    {"hasepg",                VIDEOPLAYER_HAS_EPG},
    {"parentalrating",        VIDEOPLAYER_PARENTAL_RATING},
    {"parentalratingcode",    VIDEOPLAYER_PARENTAL_RATING_CODE},
    {"parentalratingicon",    VIDEOPLAYER_PARENTAL_RATING_ICON},
    {"parentalratingsource",  VIDEOPLAYER_PARENTAL_RATING_SOURCE},
    {"isstereoscopic",        VIDEOPLAYER_IS_STEREOSCOPIC},
    {"stereoscopicmode",      VIDEOPLAYER_STEREOSCOPIC_MODE},
    {"canresumelivetv",       VIDEOPLAYER_CAN_RESUME_LIVE_TV},
    {"imdbnumber",            VIDEOPLAYER_IMDBNUMBER},
    {"episodename",           VIDEOPLAYER_EPISODENAME},
    {"dbid",                  VIDEOPLAYER_DBID},
    {"uniqueid",              VIDEOPLAYER_UNIQUEID},
    {"tvshowdbid",            VIDEOPLAYER_TVSHOWDBID},
    {"audiostreamcount",      VIDEOPLAYER_AUDIOSTREAMCOUNT},
    {"videostreamcount",      VIDEOPLAYER_VIDEOSTREAMCOUNT},
    {"hdrtype",               VIDEOPLAYER_HDR_TYPE},
    {"art",                   VIDEOPLAYER_ART},
    {"videoversionname",      VIDEOPLAYER_VIDEOVERSION_NAME},
    {"hasvideoversions",      VIDEOPLAYER_HAS_VIDEOVERSIONS},
    {"episodepart",           VIDEOPLAYER_EPISODEPART},
    {"mediaproviders",        VIDEOPLAYER_MEDIAPROVIDERS},
    {"titleextrainfo",        VIDEOPLAYER_TITLE_EXTRAINFO},
    {"hdrdetail",             VIDEOPLAYER_HDR_DETAIL},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_RetroPlayer RetroPlayer
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`RetroPlayer.Title`</b>,
///                  \anchor RetroPlayer_Title
///                  _string_,
///     @return The title of the currently-playing game.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_Title `RetroPlayer.Title`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.Platform`</b>,
///                  \anchor RetroPlayer_Platform
///                  _string_,
///     @return The platform of the currently-playing game\, or an empty string
///     if the platform is unknown.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_Platform `RetroPlayer.Platform`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.Genres`</b>,
///                  \anchor RetroPlayer_Genres
///                  _string_,
///     @return The genres of the currently-playing game\, joined by "\, ".
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_Genres `RetroPlayer.Genres`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.Publisher`</b>,
///                  \anchor RetroPlayer_Publisher
///                  _string_,
///     @return The publisher of the currently-playing game (e.g. "Nintendo").
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_Publisher `RetroPlayer.Publisher`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.Developer`</b>,
///                  \anchor RetroPlayer_Developer
///                  _string_,
///     @return The developer of the currently-playing game (e.g. "Square").
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_Developer `RetroPlayer.Developer`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.Overview`</b>,
///                  \anchor RetroPlayer_Overview
///                  _string_,
///     @return The overview/summary of the currently-playing game.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_Overview `RetroPlayer.Overview`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.GameClient`</b>,
///                  \anchor RetroPlayer_GameClient
///                  _string_,
///     @return The add-on ID of the game client (a.k.a. emulator) used to play the
///     currently-playing game (e.g. `game.libretro.beetle-psx`).
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_GameClient `RetroPlayer.GameClient`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.GameClientName`</b>,
///                  \anchor RetroPlayer_GameClientName
///                  _string_,
///     @return The emulator/core name parsed from the game client's add-on name
///     (e.g. `bsnes-mercury Performance`).
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_GameClientName `RetroPlayer.GameClientName`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.GameClientPlatforms`</b>,
///                  \anchor RetroPlayer_GameClientPlatforms
///                  _string_,
///     @return The platform or platform group supported by the game client
///     (e.g. an emulator might report "Nintendo - SNES / SFC / Game Boy / Color").
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_GameClientPlatforms `RetroPlayer.GameClientPlatforms`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.AchievementsLoggedIn`</b>,
///                  \anchor RetroPlayer_AchievementsLoggedIn
///                  _boolean_,
///     @return **True** if logged in to RetroAchievements\, **False** otherwise.
///     <p><hr>
///     @skinning_v22 **[New Boolean Condition]** \link RetroPlayer_AchievementsLoggedIn `RetroPlayer.AchievementsLoggedIn`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.AchievementsProgress`</b>,
///                  \anchor RetroPlayer_AchievementsProgress
///                  _string_,
///     @return The player's progress through the currently-playing game's
///     achievements as "earned / total" (e.g. "3 / 77")\, or an empty string if
///     the game has no achievements.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_AchievementsProgress `RetroPlayer.AchievementsProgress`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.RichPresence`</b>,
///                  \anchor RetroPlayer_RichPresence
///                  _string_,
///     @return The RetroAchievements rich presence status for the currently-playing
///     game\, or an empty string if no rich presence status is available.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_RichPresence `RetroPlayer.RichPresence`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.SupportsEject`</b>,
///                  \anchor RetroPlayer_SupportsEject
///                  _boolean_,
///     @return **True** if the game's disc can be ejected\, **False** if the
///     game isn't disc-based or doesn't support ejecting the disc.
///     <p><hr>
///     @skinning_v22 **[New Boolean Condition]** \link RetroPlayer_SupportsEject `RetroPlayer.SupportsEject`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.DiscEjected`</b>,
///                  \anchor RetroPlayer_DiscEjected
///                  _boolean_,
///     @return **True** if the game's disc is ejected (tray is open)\, **False**
///     if the game isn't disc-based or the tray is closed.
///     <p><hr>
///     @skinning_v22 **[New Boolean Condition]** \link RetroPlayer_DiscEjected `RetroPlayer.DiscEjected`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.DiscLabel`</b>,
///                  \anchor RetroPlayer_DiscLabel
///                  _string_,
///     @return The human-readable label of the currently inserted disc\, or
///     an empty string if no disc is in the tray/floppy drive or the game
///     isn't disc-based.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link RetroPlayer_DiscLabel `RetroPlayer.DiscLabel`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.EmptyTray`</b>,
///                  \anchor RetroPlayer_EmptyTray
///                  _boolean_,
///     @return **True** if the selected disc state is "No disc"\, **False** if a
///     disc is selected or the game isn't disc-based.
///     <p><hr>
///     @skinning_v22 **[New Boolean Condition]** \link RetroPlayer_EmptyTray `RetroPlayer.EmptyTray`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.VideoFilter`</b>,
///                  \anchor RetroPlayer_VideoFilter
///                  _string_,
///     @return The video filter of the currently-playing game.
///     The following values are possible:
///       - <b>`nearest`</b> (Nearest neighbor\, i.e. pixelate)
///       - <b>`linear`</b> (Bilinear filtering\, i.e. smooth blur)
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link RetroPlayer_VideoFilter `RetroPlayer.VideoFilter`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.StretchMode`</b>,
///                  \anchor RetroPlayer_StretchMode
///                  _string_,
///     @return The stretch mode of the currently-playing game.
///     The following values are possible:
///       - <b>`normal`</b> (Show the game normally)
///       - <b>`4:3`</b> (Stretch to a 4:3 aspect ratio)
///       - <b>`fullscreen`</b> (Stretch to the full viewing area)
///       - <b>`original`</b> (Shrink to the original resolution)
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link RetroPlayer_StretchMode `RetroPlayer.StretchMode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RetroPlayer.VideoRotation`</b>,
///                  \anchor RetroPlayer_VideoRotation
///                  _integer_,
///     @return The video rotation of the currently-playing game
///     in degrees counter-clockwise.
///     The following values are possible:
///       - <b>`0`</b>
///       - <b>`90`</b> (Shown in the GUI as 270 degrees)
///       - <b>`180`</b>
///       - <b>`270`</b> (Shown in the GUI as 90 degrees)
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link RetroPlayer_VideoRotation `RetroPlayer.VideoRotation`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 19> retroplayer = {{
    {"title", RETROPLAYER_TITLE},
    {"platform", RETROPLAYER_PLATFORM},
    {"genres", RETROPLAYER_GENRES},
    {"publisher", RETROPLAYER_PUBLISHER},
    {"developer", RETROPLAYER_DEVELOPER},
    {"overview", RETROPLAYER_OVERVIEW},
    {"gameclient", RETROPLAYER_GAME_CLIENT},
    {"gameclientname", RETROPLAYER_GAME_CLIENT_NAME},
    {"gameclientplatforms", RETROPLAYER_GAME_CLIENT_PLATFORMS},
    {"richpresence", RETROPLAYER_RICH_PRESENCE},
    {"achievementsloggedin", RETROPLAYER_ACHIEVEMENTS_LOGGED_IN},
    {"achievementsprogress", RETROPLAYER_ACHIEVEMENTS_PROGRESS},
    {"supportseject", RETROPLAYER_SUPPORTS_EJECT},
    {"discejected", RETROPLAYER_DISC_EJECTED},
    {"disclabel", RETROPLAYER_DISC_LABEL},
    {"emptytray", RETROPLAYER_EMPTY_TRAY},
    {"videofilter", RETROPLAYER_VIDEO_FILTER},
    {"stretchmode", RETROPLAYER_STRETCH_MODE},
    {"videorotation", RETROPLAYER_VIDEO_ROTATION},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Container Container
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Container.HasFiles`</b>,
///                  \anchor Container_HasFiles
///                  _boolean_,
///     @return **True** if the container contains files.
///     <p>
///   }
///   \table_row3{   <b>`Container.HasFolders`</b>,
///                  \anchor Container_HasFolders
///                  _boolean_,
///     @return **True** if the container contains folders.
///     <p>
///   }
///   \table_row3{   <b>`Container.IsStacked`</b>,
///                  \anchor Container_IsStacked
///                  _boolean_,
///     @return **True** if the container is currently in stacked mode.
///     <p>
///   }
///   \table_row3{   <b>`Container.FolderPath`</b>,
///                  \anchor Container_FolderPath
///                  _string_,
///     @return The complete path of currently displayed folder.
///     <p>
///   }
///   \table_row3{   <b>`Container.FolderName`</b>,
///                  \anchor Container_FolderName
///                  _string_,
///     @return The top most folder in currently displayed folder.
///     <p>
///   }
///   \table_row3{   <b>`Container.PluginName`</b>,
///                  \anchor Container_PluginName
///                  _string_,
///     @return The current plugins base folder name.
///     <p>
///   }
///   \table_row3{   <b>`Container.PluginCategory`</b>,
///                  \anchor Container_PluginCategory
///                  _string_,
///     @return The current plugins category (set by the scripter).
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Container_PluginCategory `Container.PluginCategory`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container.Viewmode`</b>,
///                  \anchor Container_Viewmode
///                  _string_,
///     @return The current viewmode (list\, icons etc).
///     <p>
///   }
///   \table_row3{   <b>`Container.ViewCount`</b>,
///                  \anchor Container_ViewCount
///                  _integer_,
///     @return The number of available skin view modes for the current container listing.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Container_ViewCount `Container.ViewCount`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container.Totaltime`</b>,
///                  \anchor Container_Totaltime
///                  _string_,
///     @return The total time of all items in the current container.
///     <p>
///   }
///   \table_row3{   <b>`Container.TotalWatched`</b>,
///                  \anchor Container_TotalWatched
///                  _string_,
///     @return The number of watched items in the container.
///     @param id - [opt] if not supplied the current container will be used.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link Container_TotalWatched `Container(id).TotalWatched`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container.TotalUnWatched`</b>,
///                  \anchor Container_TotalUnWatched
///                  _string_,
///     @return The number of unwatched items in the container.
///     @param id - [opt] if not supplied the current container will be used.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link Container_TotalUnWatched `Container(id).TotalUnWatched`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container.HasThumb`</b>,
///                  \anchor Container_HasThumb
///                  _boolean_,
///     @return **True** if the current container you are in has a thumb assigned
///     to it.
///     <p>
///   }
///   \table_row3{   <b>`Container.SortOrder`</b>,
///                  \anchor Container_SortOrder
///                  _string_,
///     @return The current sort order (Ascending/Descending).
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link Container_SortOrder `Container.SortOrder`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container.CanFilter`</b>,
///                  \anchor Container_CanFilter
///                  _boolean_,
///     @return **True** when the current container can be filtered.
///     <p>
///   }
///   \table_row3{   <b>`Container.CanFilterAdvanced`</b>,
///                  \anchor Container_CanFilterAdvanced
///                  _boolean_,
///     @return **True** when advanced filtering can be applied to the current container.
///     <p>
///   }
///   \table_row3{   <b>`Container.Filtered`</b>,
///                  \anchor Container_Filtered
///                  _boolean_,
///     @return **True** when a mediafilter is applied to the current container.
///     <p>
///   }
///   \table_row3{   <b>`Container.ShowPlot`</b>,
///                  \anchor Container_ShowPlot
///                  _string_,
///     @return The TV Show plot of the current container and can be used at
///     season and episode level.
///     <p>
///   }
///   \table_row3{   <b>`Container.ShowTitle`</b>,
///                  \anchor Container_ShowTitle
///                  _string_,
///     @return The TV Show title of the current container and can be used at
///     season and episode level.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Container_ShowTitle `Container.ShowTitle`\endlink
///     <p>
///   }
// clang-format off
constexpr std::array<InfoMap, 19> mediacontainer = {{
    {"hasfiles",          CONTAINER_HASFILES},
    {"hasfolders",        CONTAINER_HASFOLDERS},
    {"isstacked",         CONTAINER_STACKED},
    {"folderpath",        CONTAINER_FOLDERPATH},
    {"foldername",        CONTAINER_FOLDERNAME},
    {"pluginname",        CONTAINER_PLUGINNAME},
    {"plugincategory",    CONTAINER_PLUGINCATEGORY},
    {"viewmode",          CONTAINER_VIEWMODE},
    {"viewcount",         CONTAINER_VIEWCOUNT},
    {"totaltime",         CONTAINER_TOTALTIME},
    {"totalwatched",      CONTAINER_TOTALWATCHED},
    {"totalunwatched",    CONTAINER_TOTALUNWATCHED},
    {"hasthumb",          CONTAINER_HAS_THUMB},
    {"sortorder",         CONTAINER_SORT_ORDER},
    {"canfilter",         CONTAINER_CAN_FILTER},
    {"canfilteradvanced", CONTAINER_CAN_FILTERADVANCED},
    {"filtered",          CONTAINER_FILTERED},
    {"showplot",          CONTAINER_SHOWPLOT},
    {"showtitle",         CONTAINER_SHOWTITLE},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
///   \table_row3{   <b>`Container(id).OnNext`</b>,
///                  \anchor Container_OnNext
///                  _boolean_,
///     @return **True** if the container with id (or current container if id is
///     omitted) is moving to the next item. Allows views to be
///     custom-designed (such as 3D coverviews etc.)
///     <p>
///   }
///   \table_row3{   <b>`Container(id).OnScrollNext`</b>,
///                  \anchor Container_OnScrollNext
///                  _boolean_,
///     @return **True** if the container with id (or current container if id is
///     omitted) is scrolling to the next item. Differs from \ref Container_OnNext "OnNext" in that
///     \ref Container_OnNext "OnNext" triggers on movement even if there is no scroll involved.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).OnPrevious`</b>,
///                  \anchor Container_OnPrevious
///                  _boolean_,
///     @return **True** if the container with id (or current container if id is
///     omitted) is moving to the previous item. Allows views to be
///     custom-designed (such as 3D coverviews etc).
///     <p>
///   }
///   \table_row3{   <b>`Container(id).OnScrollPrevious`</b>,
///                  \anchor Container_OnScrollPrevious
///                  _boolean_,
///     @return **True** if the container with id (or current container if id is
///     omitted) is scrolling to the previous item. Differs from \ref Container_OnPrevious "OnPrevious" in
///     that \ref Container_OnPrevious "OnPrevious" triggers on movement even if there is no scroll involved.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).NumPages`</b>,
///                  \anchor Container_NumPages
///                  _integer_,
///     @return The number of pages in the container with given id. If no id is specified it
///     grabs the current container.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).NumItems`</b>,
///                  \anchor Container_NumItems
///                  _integer_,
///     @return The number of items in the container or grouplist with given id excluding parent folder item.
///     @note If no id is specified it grabs the current container.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).NumAllItems`</b>,
///                  \anchor Container_NumAllItems
///                  _integer_,
///     @return The number of all items in the container or grouplist with given id including parent folder item.
///     @note If no id is specified it grabs the current container.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link Container_NumAllItems `Container(id).NumAllItems`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container(id).NumNonFolderItems`</b>,
///                  \anchor Container_NumNonFolderItems
///                  _integer_,
///     @return The Number of items in the container or grouplist with given id excluding all folder items.
///     @note **Example:** pvr recordings folders\, parent ".." folder).
///     If no id is specified it grabs the current container.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link Container_NumNonFolderItems `Container(id).NumNonFolderItems`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container(id).CurrentPage`</b>,
///                  \anchor Container_CurrentPage
///                  _string_,
///     @return THe current page in the container with given id.
///     @note If no id is specified it grabs the current container.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).CurrentItem`</b>,
///                  \anchor Container_CurrentItem
///                  _integer_,
///     @return The current item in the container or grouplist with given id.
///     @note If no id is specified it grabs the current container.
///     <p><hr>
///     @skinning_v15 **[New Infolabel]** \link Container_CurrentItem `Container(id).CurrentItem`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container(id).Scrolling`</b>,
///                  \anchor Container_Scrolling
///                  _boolean_,
///     @return **True** if the user is currently scrolling through the container
///     with id (or current container if id is omitted).
///     @note This is slightly delayed from the actual scroll start. Use
///     \ref Container_OnScrollNext "Container(id).OnScrollNext" or
///     \ref Container_OnScrollPrevious "Container(id).OnScrollPrevious" to trigger animations
///     immediately on scroll.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).HasNext`</b>,
///                  \anchor Container_HasNext
///                  _boolean_,
///     @return **True** if the container or textbox with id (id) has a next page.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).HasParent`</b>,
///                  \anchor Container_HasParent
///                  _boolean_,
///     @return **True** when the container with given id contains a parent ('..') item.
///     @note If no id is specified it grabs the current container.
///     <p><hr>
///     @skinning_v16 **[New Boolean Condition]** \link Container_HasParent `Container.HasParent`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container(id).HasPrevious`</b>,
///                  \anchor Container_HasPrevious
///                  _boolean_,
///     @return **True** if the container or textbox with id (id) has a previous page.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).IsUpdating`</b>,
///                  \anchor Container_IsUpdating
///                  _boolean_,
///     @return **True** if the container with dynamic list content is currently updating.
///   }
// clang-format off
constexpr std::array<InfoMap, 15> container_bools = {{
    {"onnext",            CONTAINER_MOVE_NEXT},
    {"onprevious",        CONTAINER_MOVE_PREVIOUS},
    {"onscrollnext",      CONTAINER_SCROLL_NEXT},
    {"onscrollprevious",  CONTAINER_SCROLL_PREVIOUS},
    {"numpages",          CONTAINER_NUM_PAGES},
    {"numitems",          CONTAINER_NUM_ITEMS},
    {"numnonfolderitems", CONTAINER_NUM_NONFOLDER_ITEMS},
    {"numallitems",       CONTAINER_NUM_ALL_ITEMS},
    {"currentpage",       CONTAINER_CURRENT_PAGE},
    {"currentitem",       CONTAINER_CURRENT_ITEM},
    {"scrolling",         CONTAINER_SCROLLING},
    {"hasnext",           CONTAINER_HAS_NEXT},
    {"hasparent",         CONTAINER_HAS_PARENT_ITEM},
    {"hasprevious",       CONTAINER_HAS_PREVIOUS},
    {"isupdating",        CONTAINER_ISUPDATING},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
///   \table_row3{   <b>`Container(id).Row`</b>,
///                  \anchor Container_Row
///                  _integer_,
///     @return The row number of the focused position in a panel container.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link Container_Row `Container(id).Row`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container(id).Row(parameter)`</b>,
///                  \anchor Container_Row_parameter
///                  _boolean_,
///     @return **True** if the row number of the focused position matches the specified parameter.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).Column`</b>,
///                  \anchor Container_Column
///                  _integer_,
///     @return The column number of the focused position in a panel container.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link Container_Column `Container(id).Column`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container(id).Column(parameter)`</b>,
///                  \anchor Container_Column_parameter
///                  _boolean_,
///     @return **True** if the column number of the focused position matches the specified parameter.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).Position`</b>,
///                  \anchor Container_Position
///                  _integer_,
///     @return The current focused position of container / grouplist (id) as a
///     numeric label.
///     <p><hr>
///     @skinning_v16 **[Infolabel Updated]** \link Container_Position `Container(id).Position`\endlink
///     now also returns the position for items inside a grouplist.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).Position(parameter)`</b>,
///                  \anchor Container_Position_parameter
///                  _boolean_,
///     @return **True** if the container with id (or current container if id is omitted) is focused on the specified position.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).SubItem(item_number)`</b>,
///                  \anchor Container_SubItem
///                  _boolean_,
///     @return **True** if the container with id (or current container if id is omitted) is focused on the specified subitem.
///     @note If no id is specified it grabs the current container.
///     <p>
///   }
///   \table_row3{   <b>`Container(id).HasFocus(item_number)`</b>,
///                  \anchor Container_HasFocus
///                  _boolean_,
///     @return **True** if the container with id (or current container if id is
///     omitted) has static content and is focused on the item with id
///     item_number.
///     <p>
///   }
///   \table_row3{   <b>`Container.SortMethod`</b>,
///                  \anchor Container_SortMethod
///                  _string_,
///     @return The current sort method (returns a localized value).
///     <p>
///   }
///   \table_row3{   <b>`Container.SortMethod(sortid)`</b>,
///                  \anchor Container_SortMethod_sortid
///                  _boolean_,
///     @return **True** if the current sort method matches the specified SortID (see \ref List_of_sort_methods "SortUtils").
///     <p>
///   }
// clang-format off
constexpr std::array<InfoMap, 6> container_ints = {{
    {"row",         CONTAINER_ROW},
    {"column",      CONTAINER_COLUMN},
    {"position",    CONTAINER_POSITION},
    {"subitem",     CONTAINER_SUBITEM},
    {"hasfocus",    CONTAINER_HAS_FOCUS},
    {"sortmethod",  CONTAINER_SORT_METHOD},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
///   \table_row3{   <b>`Container.Property(addoncategory)`</b>,
///                  \anchor Container_Property_addoncategory
///                  _string_,
///     @return The current add-on category.
///     <p>
///   }
///   \table_row3{   <b>`Container.Property(reponame)`</b>,
///                  \anchor Container_Property_reponame
///                  _string_,
///     @return The current add-on repository name.
///     <p>
///   }
///   \table_row3{   <b>`Container.Content`</b>,
///                  \anchor Container_Content
///                  _string_,
///     @return The content of the current container.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link Container_Content `Container.Content`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container(id).ListItem(offset).Property`</b>,
///                  \anchor Container_ListItem_property
///                  _string_,
///     @return the property of the ListItem with a given offset.
///     @param offset - The offset for the listitem.
///     @note `Property` has to be replaced with `Label`\, `Label2`\, `Icon` etc.
///     @note **Example:** `Container(50).Listitem(2).Label `
///     <p>
///   }
///   \table_row3{   <b>`Container(id).ListItemNoWrap(offset).Property`</b>,
///                  \anchor Container_ListItemNoWrap
///                  _string_,
///     @return the same as \link Container_ListItem_property `Container(id).ListItem(offset).Property` \endlink
///     but it won't wrap.
///     @param offset - The offset for the listitem.
///     @note That means if the last item of a list is focused\, `ListItemNoWrap(1)`
///     will be empty while `ListItem(1)` will return the first item of the list.
///     `Property` has to be replaced with `Label`\, `Label2`\, `Icon` etc.
///     @note **Example:** `Container(50).ListitemNoWrap(1).Plot`
///     <p>
///   }
///   \table_row3{   <b>`Container(id).ListItemPosition(x).[infolabel]`</b>,
///                  \anchor Container_ListItemPosition
///                  _string_,
///     @return The infolabel for an item in a Container.
///     @param x - the position in the container relative to the cursor position.
///     @note **Example:** `Container(50).ListItemPosition(4).Genre`
///     <p>
///   }
///   \table_row3{   <b>`Container(id).ListItemAbsolute(x).[infolabel]`</b>,
///                  \anchor Container_ListItemAbsolute
///                  _string_,
///     @return The infolabel for an item in a Container.
///     @param x - the absolute position in the container.
///     @note **Example:** `Container(50).ListItemAbsolute(4).Genre`
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link Container_ListItemAbsolute `Container(id).ListItemAbsolute(x).[infolabel]`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Container.Content(parameter)`</b>,
///                  \anchor Container_Content_parameter
///                  _string_,
///     @return **True** if the current container you are in contains the following:
///       - <b>files</b>
///       - <b>songs</b>
///       - <b>artists</b>
///       - <b>albums</b>
///       - <b>movies</b>
///       - <b>tvshows</b>
///       - <b>seasons</b>
///       - <b>episodes</b>
///       - <b>musicvideos</b>
///       - <b>genres</b>
///       - <b>years</b>
///       - <b>actors</b>
///       - <b>playlists</b>
///       - <b>plugins</b>
///       - <b>studios</b>
///       - <b>directors</b>
///       - <b>sets</b>
///       - <b>tags</b>
///       - <b>videoversions</b>
///       - <b>videoassets</b>
///       - <b>videoextras</b>
///     @note These currently only work in the Video and Music
///     Library or unless a Plugin has set the value) also available are
///     Addons true when a list of add-ons is shown LiveTV true when a
///     htsp (tvheadend) directory is shown
///     <p>
///   }
///   \table_row3{   <b>`Container.Art(type)`</b>,
///                  \anchor Container_Art
///                  _string_,
///     @return The path to the art image file for the given type of the current container.
///     @param type - the art type to request.
///     @todo List of all art types
///     <p><hr>
///     @skinning_v16 **[Infolabel Updated]** \link Container_Art `Container.Art(type)`\endlink
///     <b>set.fanart</b> as possible type value.
///     @skinning_v15 **[New Infolabel]** \link Container_Art `Container.Art(type)`\endlink
///     <p>
///   }
///
// clang-format off
constexpr std::array<InfoMap, 3> container_str = {{
    {"property",  CONTAINER_PROPERTY},
    {"content",   CONTAINER_CONTENT},
    {"art",       CONTAINER_ART},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
///   \table_row3{   <b>`Container.SortDirection(direction)`</b>,
///                  \anchor Container_SortDirection
///                  _boolean_,
///     @return **True** if the sort direction of a container equals direction.
///     @param direction - The direction to check. It can be:
///       - <b>ascending</b>
///       - <b>descending</b>
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_ListItem ListItem
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`ListItem.Thumb`</b>,
///                  \anchor ListItem_Thumb
///                  _string_,
///     @return The thumbnail (if it exists) of the currently selected item
///     in a list or thumb control.
///     @deprecated but still available\, returns
///     the same as \ref ListItem_Art_Type "ListItem.Art(thumb)"
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Icon`</b>,
///                  \anchor ListItem_Icon
///                  _string_,
///     @return The thumbnail (if it exists) of the currently selected item in a list or thumb control.
///     @note If no thumbnail image exists\, it will show the icon.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ActualIcon`</b>,
///                  \anchor ListItem_ActualIcon
///                  _string_,
///     @return The icon of the currently selected item in a list or thumb control.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Overlay`</b>,
///                  \anchor ListItem_Overlay
///                  _string_,
///     @return The overlay icon status of the currently selected item in a list or thumb control.
///       - compressed file -- OverlayRAR.png
///       - watched -- OverlayWatched.png
///       - unwatched -- OverlayUnwatched.png
///       - locked -- OverlayLocked.png
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsFolder`</b>,
///                  \anchor ListItem_IsFolder
///                  _boolean_,
///     @return **True** if the current ListItem is a folder.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsPlaying`</b>,
///                  \anchor ListItem_IsPlaying
///                  _boolean_,
///     @return **True** if the current ListItem.* info labels and images are
///     currently Playing media.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsResumable`</b>,
///                  \anchor ListItem_IsResumable
///                  _boolean_,
///     @return **True** when the current ListItem has been partially played.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsCollection`</b>,
///                  \anchor ListItem_IsCollection
///                  _boolean_,
///     @return **True** when the current ListItem is a movie set.
///     <p><hr>
///     @skinning_v15 **[New Boolean Condition]** \link ListItem_IsCollection `ListItem.IsCollection`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsSelected`</b>,
///                  \anchor ListItem_IsSelected
///                  _boolean_,
///     @return **True** if the current ListItem is selected (f.e. currently playing
///     in playlist window).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.HasEpg`</b>,
///                  \anchor ListItem_HasEpg
///                  _boolean_,
///     @return **True** when the selected programme has epg info (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.HasTimer`</b>,
///                  \anchor ListItem_HasTimer
///                  _boolean_,
///     @return **True** when a recording timer has been set for the selected
///     programme (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsRecording`</b>,
///                  \anchor ListItem_IsRecording
///                  _boolean_,
///     @return **True** when the selected programme is being recorded (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsPlayable`</b>,
///                  \anchor ListItem_IsPlayable
///                  _boolean_,
///     @return **True** when the selected programme can be played (PVR)
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link ListItem_IsPlayable `ListItem.IsPlayable`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.HasArchive`</b>,
///                  \anchor ListItem_HasArchive
///                  _boolean_,
///     @return **True** when the selected channel has a server-side back buffer (PVR)
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link ListItem_HasArchive `ListItem.HasArchive`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsEncrypted`</b>,
///                  \anchor ListItem_IsEncrypted
///                  _boolean_,
///     @return **True** when the selected programme is encrypted (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsStereoscopic`</b>,
///                  \anchor ListItem_IsStereoscopic
///                  _boolean_,
///     @return **True** when the selected video is a 3D (stereoscopic) video.
///     <p><hr>
///     @skinning_v13 **[New Boolean Condition]** \link ListItem_IsStereoscopic `ListItem.IsStereoscopic`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(IsSpecial)`</b>,
///                  \anchor ListItem_Property_IsSpecial
///                  _boolean_,
///     @return **True** if the current Season/Episode is a Special.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(isbookmark)`</b>,
///                  \anchor ListItem_Property_IsBookmark
///                  _boolean_,
///     @return **True** if the item is a bookmark.
///     @note Only set on items in the video bookmarks dialog.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(ischapter)`</b>,
///                  \anchor ListItem_Property_IsChapter
///                  _boolean_,
///     @return **True** if the item is a chapter.
///     @note Only set on items in the video bookmarks dialog.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(DateLabel)`</b>,
///                  \anchor ListItem_Property_DateLabel
///                  _boolean_,
///     @return **True** if the item is a date label\, returns false if the item is a time label.
///     @note Can be used in the rulerlayout of the epggrid control.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.IsEnabled)`</b>,
///                  \anchor ListItem_Property_AddonIsEnabled
///                  _boolean_,
///     @return **True** when the selected addon is enabled (for use in the addon
///     info dialog only).
///     <p><hr>
///     @skinning_v17 **[Boolean Condition Updated]** \link ListItem_Property_AddonIsEnabled `ListItem.Property(Addon.IsEnabled)`\endlink
///     replaces `ListItem.Property(Addon.Enabled)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.IsInstalled)`</b>,
///                  \anchor ListItem_Property_AddonIsInstalled
///                  _boolean_,
///     @return **True** when the selected addon is installed (for use in the addon
///     info dialog only).
///     <p><hr>
///     @skinning_v17 **[Boolean Condition Updated]** \link ListItem_Property_AddonIsInstalled `ListItem.Property(Addon.IsInstalled)`\endlink
///     replaces `ListItem.Property(Addon.Installed)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.HasUpdate)`</b>,
///                  \anchor ListItem_Property_AddonHasUpdate
///                  _boolean_,
///     @return **True** when there's an update available for the selected addon.
///     <p><hr>
///     @skinning_v17 **[Boolean Condition Updated]** \link ListItem_Property_AddonHasUpdate `ListItem.Property(Addon.HasUpdate)`\endlink
///     replaces `ListItem.Property(Addon.UpdateAvail)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsAutoUpdateable`</b>,
///                  \anchor ListItem_IsAutoUpdateable
///                  _boolean_,
///     @return **True** if this add-on can be updated automatically.
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link ListItem_IsAutoUpdateable `ListItem.IsAutoUpdateable`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.IsFromOfficialRepo)`</b>,
///                  \anchor ListItem_Property_AddonIsFromOfficialRepo
///                  _boolean_,
///     @return **True** if this add-on is from an official repository.
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link ListItem_Property_AddonIsFromOfficialRepo `ListItem.Property(Addon.IsFromOfficialRepo)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.IsBinary)`</b>,
///                  \anchor ListItem_Property_AddonIsBinary
///                  _boolean_,
///     @return **True** if this add-on is a binary addon.
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link ListItem_Property_AddonIsBinary `ListItem.Property(Addon.IsBinary)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.IsUpdate)`</b>,
///                  \anchor ListItem_Property_AddonIsUpdate
///                  _boolean_,
///     @return **True** if this add-on is a valid update of an installed outdated add-on.
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link ListItem_Property_AddonIsUpdate `ListItem.Property(Addon.IsUpdate)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.ValidUpdateOrigin)`</b>,
///                  \anchor ListItem_Property_ValidUpdateOrigin
///                  _string_,
///     @return The origin string of a valid update for the addon. Empty string if there is no valid update available.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_Property_ValidUpdateOrigin `ListItem.Property(Addon.ValidUpdateOrigin)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.ValidUpdateVersion)`</b>,
///                  \anchor ListItem_Property_ValidUpdateVersion
///                  _string_,
///     @return The version string of a valid update for the addon. Empty string if there is no valid update available.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_Property_ValidUpdateVersion `ListItem.Property(Addon.ValidUpdateVersion)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Label`</b>,
///                  \anchor ListItem_Label
///                  _string_,
///     @return The left label of the currently selected item in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Label2`</b>,
///                  \anchor ListItem_Label2
///                  _string_,
///     @return The right label of the currently selected item in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Title`</b>,
///                  \anchor ListItem_Title
///                  _string_,
///     @return The title of the currently selected song\, movie\, game in a container.
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link ListItem_Title `ListItem.Title`\endlink extended
///     to support games
///     <p>
///   }
///   \table_row3{   <b>`ListItem.OriginalTitle`</b>,
///                  \anchor ListItem_OriginalTitle
///                  _string_,
///     @return The original title of the currently selected movie in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.SortLetter`</b>,
///                  \anchor ListItem_SortLetter
///                  _string_,
///     @return The first letter of the current file in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.TrackNumber`</b>,
///                  \anchor ListItem_TrackNumber
///                  _string_,
///     @return The track number of the currently selected song in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Artist`</b>,
///                  \anchor ListItem_Artist
///                  _string_,
///     @return The artist of the currently selected song in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AlbumArtist`</b>,
///                  \anchor ListItem_AlbumArtist
///                  _string_,
///     @return The artist of the currently selected album in a list.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Sortname)`</b>,
///                  \anchor ListItem_Property_Artist_Sortname
///                  _string_,
///     @return The sortname of the currently selected Artist.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Property_Artist_Sortname `ListItem.Property(Artist_Sortname)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Type)`</b>,
///                  \anchor ListItem_Property_Artist_Type
///                  _string_,
///     @return The type of the currently selected Artist - person\, group\, orchestra\, choir etc.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Property_Artist_Type `ListItem.Property(Artist_Type)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Gender)`</b>,
///                  \anchor ListItem_Property_Artist_Gender
///                  _string_,
///     @return The Gender of the currently selected Artist - male\, female\, other.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Property_Artist_Gender `ListItem.Property(Artist_Gender)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Disambiguation)`</b>,
///                  \anchor ListItem_Property_Artist_Disambiguation
///                  _string_,
///     @return A Brief description of the currently selected Artist that differentiates them
///     from others with the same name.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Property_Artist_Disambiguation `ListItem.Property(Artist_Disambiguation)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Born)`</b>,
///                  \anchor ListItem_Property_Artist_Born
///                  _string_,
///     @return The date of Birth of the currently selected Artist.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Died)`</b>,
///                  \anchor ListItem_Property_Artist_Died
///                  _string_,
///     @return The date of Death of the currently selected Artist.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Formed)`</b>,
///                  \anchor ListItem_Property_Artist_Formed
///                  _string_,
///     @return The formation date of the currently selected Band.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Disbanded)`</b>,
///                  \anchor ListItem_Property_Artist_Disbanded
///                  _string_,
///     @return The disbanding date of the currently selected Band.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_YearsActive)`</b>,
///                  \anchor ListItem_Property_Artist_YearsActive
///                  _string_,
///     @return The years the currently selected artist has been active.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Instrument)`</b>,
///                  \anchor ListItem_Property_Artist_Instrument
///                  _string_,
///     @return The instruments played by the currently selected artist.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Description)`</b>,
///                  \anchor ListItem_Property_Artist_Description
///                  _string_,
///     @return A biography of the currently selected artist.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Mood)`</b>,
///                  \anchor ListItem_Property_Artist_Mood
///                  _string_,
///     @return The moods of the currently selected artist.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Style)`</b>,
///                  \anchor ListItem_Property_Artist_Style
///                  _string_,
///     @return The styles of the currently selected artist.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Artist_Genre)`</b>,
///                  \anchor ListItem_Property_Artist_Genre
///                  _string_,
///     @return The genre of the currently selected artist.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Album`</b>,
///                  \anchor ListItem_Album
///                  _string_,
///     @return The album of the currently selected song in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Album_Mood)`</b>,
///                  \anchor ListItem_Property_Album_Mood
///                  _string_,
///     @return The moods of the currently selected Album.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Album_Style)`</b>,
///                  \anchor ListItem_Property_Album_Style
///                  _string_,
///     @return The styles of the currently selected Album.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Album_Theme)`</b>,
///                  \anchor ListItem_Property_Album_Theme
///                  _string_,
///     @return The themes of the currently selected Album.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Album_Type)`</b>,
///                  \anchor ListItem_Property_Album_Type
///                  _string_,
///     @return The Album Type (e.g. compilation\, enhanced\, explicit lyrics) of
///     the currently selected Album.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Album_Label)`</b>,
///                  \anchor ListItem_Property_Album_Label
///                  _string_,
///     @return The record label of the currently selected Album.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Album_Description)`</b>,
///                  \anchor ListItem_Property_Album_Description
///                  _string_,
///     @return A review of the currently selected Album.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Album_Totaldiscs)`</b>,
///                  \anchor ListItem_Property_Album_Totaldiscs
///                  _string_,
///     @return The total number of discs belonging to an album.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_Property_Album_Totaldiscs `ListItem.Property(Album_Totaldiscs)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Album_Isboxset)`</b>,
///                  \anchor ListItem_Property_Album_Isboxset
///                  _string_,
///     @return **True** if the album is a boxset.
///     <p><hr>
///     @skinning_v19 **[New Infobool]** \link ListItem_Property_Album_Isboxset `ListItem.Property(Album_Isboxset)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Album_Duration)`</b>,
///                  \anchor ListItem_Property_Album_Duration
///                  _string_,
///     @return The duration of the album in HH:MM:SS.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_Property_Album_Duration `ListItem.Property(Album_Duration)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.DiscNumber`</b>,
///                  \anchor ListItem_DiscNumber
///                  _string_,
///     @return The disc number of the currently selected song in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Year`</b>,
///                  \anchor ListItem_Year
///                  _string_,
///     @return The year of the currently selected song\, album\, movie\, game  in a
///     container.
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link ListItem_Title `ListItem.Title`\endlink extended
///     to support games
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Premiered`</b>,
///                  \anchor ListItem_Premiered
///                  _string_,
///     @return The release/aired date of the currently selected episode\, show\,
///     movie or EPG item in a container.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link ListItem_Premiered `ListItem.Premiered`\endlink
///     now also available for EPG items.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Genre`</b>,
///                  \anchor ListItem_Genre
///                  _string_,
///     @return The genre of the currently selected song\, album or movie in a
///     container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Genre(separator)`</b>,
///                  \anchor ListItem_Genre_separator
///                  _string_,
///     @return A list of genres\, separated by given separator\, or if no separator was given
///     separated by the advanced settings value \“itemseparator\” for videos or music.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_Genre_separator `ListItem.Genre(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Contributors`</b>,
///                  \anchor ListItem_Contributors
///                  _string_,
///     @return The list of all people who've contributed to the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Contributors `ListItem.Contributors`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ContributorAndRole`</b>,
///                  \anchor ListItem_ContributorAndRole
///                  _string_,
///     @return The list of all people and their role who've contributed to the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_ContributorAndRole `ListItem.ContributorAndRole`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Director`</b>,
///                  \anchor ListItem_Director
///                  _string_,
///     @return The director of the currently selected movie in a container.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link ListItem_Director `ListItem.Director`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Director(separator)`</b>,
///                  \anchor ListItem_Director_separator
///                  _string_,
///     @return A list of directors\, separated by given separator\, or if no separator was given
///     separated by the advanced settings value \“itemseparator\” for video items.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_Director_separator `ListItem.Director(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Country`</b>,
///                  \anchor ListItem_Country
///                  _string_,
///     @return The production country of the currently selected movie in a
///     container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Episode`</b>,
///                  \anchor ListItem_Episode
///                  _string_,
///     @return The episode number value for the currently selected episode. It
///     also returns the number of total\, watched or unwatched episodes for the
///     currently selected tvshow or season\, based on the the current watched
///     filter.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link ListItem_Episode `ListItem.Episode`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Season`</b>,
///                  \anchor ListItem_Season
///                  _string_,
///     @return The season value for the currently selected tvshow.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link ListItem_Season `ListItem.Season`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.TVShowTitle`</b>,
///                  \anchor ListItem_TVShowTitle
///                  _string_,
///     @return The name value for the currently selected tvshow in the season and
///     episode depth of the video library.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(TotalSeasons)`</b>,
///                  \anchor ListItem_Property_TotalSeasons
///                  _string_,
///     @return The total number of seasons for the currently selected tvshow.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(TotalEpisodes)`</b>,
///                  \anchor ListItem_Property_TotalEpisodes
///                  _string_,
///     @return the total number of episodes for the currently selected tvshow or
///     season.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(WatchedEpisodes)`</b>,
///                  \anchor ListItem_Property_WatchedEpisodes
///                  _string_,
///     @return The number of watched episodes for the currently selected tvshow
///     or season.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(UnWatchedEpisodes)`</b>,
///                  \anchor ListItem_Property_UnWatchedEpisodes
///                  _string_,
///     @return The number of unwatched episodes for the currently selected tvshow
///     or season.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(NumEpisodes)`</b>,
///                  \anchor ListItem_Property_NumEpisodes
///                  _string_,
///     @return The number of total\, watched or unwatched episodes for the
///     currently selected tvshow or season\, based on the the current watched filter.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(WatchedEpisodePercent)`</b>,
///                  \anchor ListItem_Property_WatchedEpisodePercent
///                  _string_,
///     @return The percentage of watched episodes in the tvshow (watched/total*100) or season.
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link ListItem_Property_WatchedEpisodePercent `ListItem.Property(WatchedEpisodePercent)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureAperture`</b>,
///                  \anchor ListItem_PictureAperture
///                  _string_,
///     @return The F-stop used to take the selected picture.
///     @note This is the value of the EXIF FNumber tag (hex code 0x829D).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureAuthor`</b>,
///                  \anchor ListItem_PictureAuthor
///                  _string_,
///     @return The name of the person involved in writing about the selected picture.
///     @note This is the value of the IPTC Writer tag (hex code 0x7A).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureAuthor `ListItem.PictureAuthor`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureByline`</b>,
///                  \anchor ListItem_PictureByline
///                  _string_,
///     @return The name of the person who created the selected picture.
///     @note This is the value of the IPTC Byline tag (hex code 0x50).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureByline `ListItem.PictureByline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureBylineTitle`</b>,
///                  \anchor ListItem_PictureBylineTitle
///                  _string_,
///     @return The title of the person who created the selected picture.
///     @note This is the value of the IPTC BylineTitle tag (hex code 0x55).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureBylineTitle `ListItem.PictureBylineTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureCamMake`</b>,
///                  \anchor ListItem_PictureCamMake
///                  _string_,
///     @return The manufacturer of the camera used to take the selected picture.
///     @note This is the value of the EXIF Make tag (hex code 0x010F).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureCamModel`</b>,
///                  \anchor ListItem_PictureCamModel
///                  _string_,
///     @return The manufacturer's model name or number of the camera used to take
///     the selected picture.
///     @note This is the value of the EXIF Model tag (hex code 0x0110).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureCaption`</b>,
///                  \anchor ListItem_PictureCaption
///                  _string_,
///     @return A description of the selected picture.
///     @note This is the value of the IPTC Caption tag (hex code 0x78).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureCategory`</b>,
///                  \anchor ListItem_PictureCategory
///                  _string_,
///     @return The subject of the selected picture as a category code.
///     @note This is the value of the IPTC Category tag (hex code 0x0F).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureCategory `ListItem.PictureCategory`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureCCDWidth`</b>,
///                  \anchor ListItem_PictureCCDWidth
///                  _string_,
///     @return The width of the CCD in the camera used to take the selected
///     picture.
///     @note This is calculated from three EXIF tags (0xA002 * 0xA210 / 0xA20e).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureCCDWidth `ListItem.PictureCCDWidth`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureCity`</b>,
///                  \anchor ListItem_PictureCity
///                  _string_,
///     @return The city where the selected picture was taken.
///     @note This is the value of the IPTC City tag (hex code 0x5A).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureCity `ListItem.PictureCity`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureColour`</b>,
///                  \anchor ListItem_PictureColour
///                  _string_,
///     @return Whether the selected picture is "Colour" or "Black and White".
///     <p>
///     @deprecated \link ListItem_PictureColour `ListItem.PictureColour`\endlink is deprecated and will be removed in future Kodi versions
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureColour `ListItem.PictureColour`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureComment`</b>,
///                  \anchor ListItem_PictureComment
///                  _string_,
///     @return A description of the selected picture.
///     @note This is the value of the
///     EXIF User Comment tag (hex code 0x9286). This is the same value as
///     \ref Slideshow_SlideComment "Slideshow.SlideComment".
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureCopyrightNotice`</b>,
///                  \anchor ListItem_PictureCopyrightNotice
///                  _string_,
///     @return The copyright notice of the selected picture.
///     @note This is the value of the IPTC Copyright tag (hex code 0x74).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureCopyrightNotice `ListItem.PictureCopyrightNotice`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureCountry`</b>,
///                  \anchor ListItem_PictureCountry
///                  _string_,
///     @return The full name of the country where the selected picture was taken.
///     @note This is the value of the IPTC CountryName tag (hex code 0x65).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureCountry `ListItem.PictureCountry`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureCountryCode`</b>,
///                  \anchor ListItem_PictureCountryCode
///                  _string_,
///     @return The country code of the country where the selected picture was
///     taken.
///     @note This is the value of the IPTC CountryCode tag (hex code 0x64).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureCountryCode `ListItem.PictureCountryCode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureCredit`</b>,
///                  \anchor ListItem_PictureCredit
///                  _string_,
///     @return Who provided the selected picture.
///     @note This is the value of the IPTC Credit tag (hex code 0x6E).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureCredit `ListItem.PictureCredit`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureDate`</b>,
///                  \anchor ListItem_PictureDate
///                  _string_,
///     @return The localized date of the selected picture. The short form of the
///     date is used.
///     @note The value of the EXIF DateTimeOriginal tag (hex code 0x9003)
///     is preferred. If the DateTimeOriginal tag is not found\, the value of
///     DateTimeDigitized (hex code 0x9004) or of DateTime (hex code 0x0132) might
///     be used.
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureDate `ListItem.PictureDate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureDatetime`</b>,
///                  \anchor ListItem_PictureDatetime
///                  _string_,
///     @return The date/timestamp of the selected picture. The localized short form
///     of the date and time is used.
///     @note The value of the EXIF DateTimeOriginal tag (hex code 0x9003) is preferred.
///     If the DateTimeOriginal tag is not found\, the value of DateTimeDigitized
///     (hex code 0x9004) or of DateTime (hex code 0x0132) might be used.
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureDatetime `ListItem.PictureDatetime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureDesc`</b>,
///                  \anchor ListItem_PictureDesc
///                  _string_,
///     @return A short description of the selected picture. The SlideComment\,
///     EXIFComment\, or Caption values might contain a longer description.
///     @note This is the value of the EXIF ImageDescription tag (hex code 0x010E).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureDigitalZoom`</b>,
///                  \anchor ListItem_PictureDigitalZoom
///                  _string_,
///     @return The digital zoom ratio when the selected picture was taken.
///     @note This is the value of the EXIF DigitalZoomRatio tag (hex code 0xA404).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureDigitalZoom `ListItem.PictureDigitalZoom`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureExpMode`</b>,
///                  \anchor ListItem_PictureExpMode
///                  _string_,
///     @return The exposure mode of the selected picture.
///     The possible values are:
///       - <b>"Automatic"</b>
///       - <b>"Manual"</b>
///       - <b>"Auto bracketing"</b>
///     @note This is the value of the EXIF ExposureMode tag (hex code 0xA402).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureExposure`</b>,
///                  \anchor ListItem_PictureExposure
///                  _string_,
///     @return The class of the program used by the camera to set exposure when
///     the selected picture was taken. Values include:
///      -  <b>"Manual"</b>
///      -  <b>"Program (Auto)"</b>
///      -  <b>"Aperture priority (Semi-Auto)"</b>
///      -  <b>"Shutter priority (semi-auto)"</b>
///      -  etc
///     @note This is the value of the EXIF ExposureProgram tag (hex code 0x8822).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureExposure `ListItem.PictureExposure`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureExposureBias`</b>,
///                  \anchor ListItem_PictureExposureBias
///                  _string_,
///     @return The exposure bias of the selected picture.
///     Typically this is a number between -99.99 and 99.99.
///     @note This is the value of the EXIF ExposureBiasValue tag (hex code 0x9204).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureExposureBias `ListItem.PictureExposureBias`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureExpTime`</b>,
///                  \anchor ListItem_PictureExpTime
///                  _string_,
///     @return The exposure time of the selected picture\, in seconds.
///     @note This is the value of the EXIF ExposureTime tag (hex code 0x829A).
///     If the ExposureTime tag is not found\, the ShutterSpeedValue tag (hex code 0x9201)
///     might be used.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureFlashUsed`</b>,
///                  \anchor ListItem_PictureFlashUsed
///                  _string_,
///     @return The status of flash when the selected picture was taken. The value
///     will be either "Yes" or "No"\, and might include additional information.
///     @note This is the value of the EXIF Flash tag (hex code 0x9209).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureFlashUsed `ListItem.PictureFlashUsed`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureFocalLen`</b>,
///                  \anchor ListItem_PictureFocalLen
///                  _string_,
///     @return The lens focal length of the selected picture.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureFocusDist`</b>,
///                  \anchor ListItem_PictureFocusDist
///                  _string_,
///     @return The focal length of the lens\, in mm.
///     @note This is the value of the EXIF FocalLength tag (hex code 0x920A).
///   }
///   \table_row3{   <b>`ListItem.PictureGPSLat`</b>,
///                  \anchor ListItem_PictureGPSLat
///                  _string_,
///     @return The latitude where the selected picture was taken (degrees\,
///     minutes\, seconds North or South).
///     @note This is the value of the EXIF GPSInfo.GPSLatitude and GPSInfo.GPSLatitudeRef tags.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureGPSLon`</b>,
///                  \anchor ListItem_PictureGPSLon
///                  _string_,
///     @return The longitude where the selected picture was taken (degrees\,
///     minutes\, seconds East or West).
///     @note This is the value of the EXIF GPSInfo.GPSLongitude and GPSInfo.GPSLongitudeRef tags.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureGPSAlt`</b>,
///                  \anchor ListItem_PictureGPSAlt
///                  _string_,
///     @return The altitude in meters where the selected picture was taken.
///     @note This is the value of the EXIF GPSInfo.GPSAltitude tag.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureHeadline`</b>,
///                  \anchor ListItem_PictureHeadline
///                  _string_,
///     @return A synopsis of the contents of the selected picture.
///     @note This is the value of the IPTC Headline tag (hex code 0x69).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureHeadline `ListItem.PictureHeadline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureImageType`</b>,
///                  \anchor ListItem_PictureImageType
///                  _string_,
///     @return The color components of the selected picture.
///     @note This is the value of the IPTC ImageType tag (hex code 0x82).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureImageType `ListItem.PictureImageType`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureIPTCDate`</b>,
///                  \anchor ListItem_PictureIPTCDate
///                  _string_,
///     @return The date when the intellectual content of the selected picture was
///     created\, rather than when the picture was created.
///     @note This is the value of the IPTC DateCreated tag (hex code 0x37).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureIPTCDate `ListItem.PictureIPTCDate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureIPTCTime`</b>,
///                  \anchor ListItem_PictureIPTCTime
///                  _string_,
///     @return The time when the intellectual content of the selected picture was
///     created\, rather than when the picture was created.
///     @note This is the value of the IPTC TimeCreated tag (hex code 0x3C).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureIPTCTime `ListItem.PictureIPTCTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureISO`</b>,
///                  \anchor ListItem_PictureISO
///                  _string_,
///     @return The ISO speed of the camera when the selected picture was taken.
///     @note This is the value of the EXIF ISOSpeedRatings tag (hex code 0x8827).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureKeywords`</b>,
///                  \anchor ListItem_PictureKeywords
///                  _string_,
///     @return The keywords assigned to the selected picture.
///     @note This is the value of the IPTC Keywords tag (hex code 0x19).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureLightSource`</b>,
///                  \anchor ListItem_PictureLightSource
///                  _string_,
///     @return The kind of light source when the picture was taken. Possible
///     values include:
///       - <b>"Daylight"</b>
///       - <b>"Fluorescent"</b>
///       - <b>"Incandescent"</b>
///       - etc
///     @note This is the value of the EXIF LightSource tag (hex code 0x9208).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureLightSource `ListItem.PictureLightSource`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureLongDate`</b>,
///                  \anchor ListItem_PictureLongDate
///                  _string_,
///     @return Only the localized date of the selected picture. The long form of
///     the date is used.
///     @note The value of the EXIF DateTimeOriginal tag (hex code
///     0x9003) is preferred. If the DateTimeOriginal tag is not found\, the
///     value of DateTimeDigitized (hex code 0x9004) or of DateTime (hex code
///     0x0132) might be used.
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureLongDate `ListItem.PictureLongDate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureLongDatetime`</b>,
///                  \anchor ListItem_PictureLongDatetime
///                  _string_,
///     @return The date/timestamp of the selected picture. The localized long
///     form of the date and time is used.
///     @note The value of the EXIF DateTimeOriginal
///     tag (hex code 0x9003) is preferred. if the DateTimeOriginal tag is not
///     found\, the value of DateTimeDigitized (hex code 0x9004) or of DateTime
///     (hex code 0x0132) might be used.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureMeteringMode`</b>,
///                  \anchor ListItem_PictureMeteringMode
///                  _string_,
///     @return The metering mode used when the selected picture was taken. The
///     possible values are:
///      - <b>"Center weight"</b>
///      - <b>"Spot"</b>
///      - <b>"Matrix"</b>
///     @note This is the value of the EXIF MeteringMode tag (hex code 0x9207).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureMeteringMode `ListItem.PictureMeteringMode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureObjectName`</b>,
///                  \anchor ListItem_PictureObjectName
///                  _string_,
///     @return A shorthand reference for the selected picture.
///     @note This is the value of the IPTC ObjectName tag (hex code 0x05).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureObjectName `ListItem.PictureObjectName`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureOrientation`</b>,
///                  \anchor ListItem_PictureOrientation
///                  _string_,
///     @return The orientation of the selected picture. Possible values are:
///       - <b>"Top Left"</b>
///       - <b>"Top Right"</b>
///       - <b>"Left Top"</b>
///       - <b>"Right Bottom"</b>
///       - etc
///     @note This is the value of the EXIF Orientation tag (hex code 0x0112).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureOrientation `ListItem.PictureOrientation`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PicturePath`</b>,
///                  \anchor ListItem_PicturePath
///                  _string_,
///     @return The filename and path of the selected picture.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureProcess`</b>,
///                  \anchor ListItem_PictureProcess
///                  _string_,
///     @return The process used to compress the selected picture.
///     <p>
///     @deprecated \link ListItem_PictureProcess `ListItem.PictureProcess`\endlink is deprecated and will be removed in future Kodi versions
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureProcess `ListItem.PictureProcess`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureReferenceService`</b>,
///                  \anchor ListItem_PictureReferenceService
///                  _string_,
///     @return The Service Identifier of a prior envelope to which the selected
///     picture refers.
///     @note This is the value of the IPTC ReferenceService tag (hex code 0x2D).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureReferenceService `ListItem.PictureReferenceService`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureResolution`</b>,
///                  \anchor ListItem_PictureResolution
///                  _string_,
///     @return The dimensions of the selected picture.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureSource`</b>,
///                  \anchor ListItem_PictureSource
///                  _string_,
///     @return The original owner of the selected picture.
///     @note This is the value of the IPTC Source tag (hex code 0x73).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureSource `ListItem.PictureSource`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureSpecialInstructions`</b>,
///                  \anchor ListItem_PictureSpecialInstructions
///                  _string_,
///     @return Other editorial instructions concerning the use of the selected
///     picture.
///     @note This is the value of the IPTC SpecialInstructions tag (hex code 0x28).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureSpecialInstructions `ListItem.PictureSpecialInstructions`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureState`</b>,
///                  \anchor ListItem_PictureState
///                  _string_,
///     @return The State/Province where the selected picture was taken.
///     @note This is the value of the IPTC ProvinceState tag (hex code 0x5F).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureState `ListItem.PictureState`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureSublocation`</b>,
///                  \anchor ListItem_PictureSublocation
///                  _string_,
///     @return The location within a city where the selected picture was taken -
///     might indicate the nearest landmark.
///     @note This is the value of the IPTC SubLocation tag (hex code 0x5C).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureSublocation `ListItem.PictureSublocation`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureSupplementalCategories`</b>,
///                  \anchor ListItem_PictureSupplementalCategories
///                  _string_,
///     @return A supplemental category codes to further refine the subject of the
///     selected picture.
///     @note This is the value of the IPTC SuppCategory tag (hex code 0x14).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureSupplementalCategories `ListItem.PictureSupplementalCategories`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureTransmissionReference`</b>,
///                  \anchor ListItem_PictureTransmissionReference
///                  _string_,
///     @return A code representing the location of original transmission of the
///     selected picture.
///     @note This is the value of the IPTC TransmissionReference tag (hex code 0x67).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureTransmissionReference `ListItem.PictureTransmissionReference`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureUrgency`</b>,
///                  \anchor ListItem_PictureUrgency
///                  _string_,
///     @return The urgency of the selected picture. Values are 1-9.
///     @note The "1" is most urgent. Some image management programs use urgency to indicate
///     picture rating\, where urgency "1" is 5 stars and urgency "5" is 1 star.
///     Urgencies 6-9 are not used for rating. This is the value of the IPTC
///     Urgency tag (hex code 0x0A).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureUrgency `ListItem.PictureUrgency`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PictureWhiteBalance`</b>,
///                  \anchor ListItem_PictureWhiteBalance
///                  _string_,
///     @return The white balance mode set when the selected picture was taken.
///     The possible values are:
///       - <b>"Manual"</b>
///       - <b>"Auto"</b>
///     @note This is the value of the EXIF WhiteBalance tag (hex code 0xA403).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_PictureWhiteBalance `ListItem.PictureWhiteBalance`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.FileName`</b>,
///                  \anchor ListItem_FileName
///                  _string_,
///     @return The filename of the currently selected song or movie in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Path`</b>,
///                  \anchor ListItem_Path
///                  _string_,
///     @return The complete path of the currently selected song or movie in a
///     container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.FolderName`</b>,
///                  \anchor ListItem_FolderName
///                  _string_,
///     @return The top most folder of the path of the currently selected song or
///     movie in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.FolderPath`</b>,
///                  \anchor ListItem_FolderPath
///                  _string_,
///     @return The complete path of the currently selected song or movie in a
///     container (without user details).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.FileNameAndPath`</b>,
///                  \anchor ListItem_FileNameAndPath
///                  _string_,
///     @return The full path with filename of the currently selected song or
///     movie in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.DecodedFileNameAndPath`</b>,
///                  \anchor ListItem_DecodedFileNameAndPath
///                  _string_,
///     @return The full path with filename of the currently selected song or
///     movie in a container decoded - made more human readable.
///     For example bluray://smb%3A%2F%2Fsomepath%2Fmovie.iso/BDMV/PLAYLIST/00000.mpls
///     becomes bluray://smb://somepath/movie.iso/BDMV/PLAYLIST/00000.mpls
///     <p>
///   }
///   \table_row3{   <b>`ListItem.FileExtension`</b>,
///                  \anchor ListItem_FileExtension
///                  _string_,
///     @return The file extension (without leading dot) of the currently selected
///     item in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.FileNameNoExtension`</b>,
///                  \anchor ListItem_FileName_No_Extension
///                  _string_,
///     @return The filename without extension of the currently selected
///     item in a container.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_FileName_No_Extension `ListItem.FileNameNoExtension`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Date`</b>,
///                  \anchor ListItem_Date
///                  _string_,
///     @return The file date of the currently selected song or movie in a
///     container / Aired date of an episode / Day\, start time and end time of
///     current selected TV programme (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.DateTime`</b>,
///                  \anchor ListItem_DateTime
///                  _string_,
///     @return The date and time a certain event happened (event log).
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link ListItem_DateTime `ListItem.DateTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.DateAdded`</b>,
///                  \anchor ListItem_DateAdded
///                  _string_,
///     @return The date the currently selected item was added to the
///     library / Date and time of an event in the EventLog window.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Size`</b>,
///                  \anchor ListItem_Size
///                  _string_,
///     @return The file size of the currently selected song or movie in a
///     container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Rating([name])`</b>,
///                  \anchor ListItem_Rating
///                  _string_,
///     @return The scraped rating of the currently selected item in a container (1-10).
///     @param name - [opt] you can specify the name of the scraper to retrieve a specific rating\,
///     for use in dialogvideoinfo.xml.
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link ListItem_Rating `ListItem.Rating([name])`\endlink replaces
///     the old `ListItem.Ratings([name])` infolabel.
///     @skinning_v17 **[New Infolabel]** \link ListItem_Rating `ListItem.Ratings([name])`\endlink
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_Rating `ListItem.Ratings`\endlink
///     for songs it's now the scraped rating.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Set`</b>,
///                  \anchor ListItem_Set
///                  _string_,
///     @return The name of the set the movie is part of.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Set `ListItem.Set`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.SetId`</b>,
///                  \anchor ListItem_SetId
///                  _string_,
///     @return The id of the set the movie is part of.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_SetId `ListItem.SetId`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Status`</b>,
///                  \anchor ListItem_Status
///                  _string_,
///     @return One of the following status:
///       - <b>"returning series"</b>
///       - <b>"in production"</b>
///       - <b>"planned"</b>
///       - <b>"cancelled"</b>
///       - <b>"ended"</b>
///     <p>
///     @note For use with tv shows.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Status `ListItem.Status`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.EndTimeResume`</b>,
///                  \anchor ListItem_EndTimeResume
///                  _string_,
///     @return Returns the time a video will end if you resume it\, instead of playing it from the beginning.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_EndTimeResume `ListItem.EndTimeResume`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.UserRating`</b>,
///                  \anchor ListItem_UserRating
///                  _string_,
///     @return The user rating of the currently selected item in a container (1-10).
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_UserRating `ListItem.UserRating`\endlink
///     now available for albums/songs.
///     @skinning_v16 **[New Infolabel]** \link ListItem_UserRating `ListItem.UserRating`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Votes([name])`</b>,
///                  \anchor ListItem_Votes
///                  _string_,
///     @return The scraped votes of the currently selected movie in a container.
///     @param name - [opt] you can specify the name of the scraper to retrieve specific votes\,
///     for use in `dialogvideoinfo.xml`.
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_Votes `ListItem.Votes([name])`\endlink
///     add optional param <b>name</b> to specify the scrapper.
///     @skinning_v13 **[New Infolabel]** \link ListItem_Votes `ListItem.Votes`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.RatingAndVotes([name])`</b>,
///                  \anchor ListItem_RatingAndVotes
///                  _string_,
///     @return The scraped rating and votes of the currently selected movie in a
///     container (1-10).
///     @param name - [opt] you can specify the name of the scraper to retrieve specific votes\,
///     for use in `dialogvideoinfo.xml`.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_RatingAndVotes `ListItem.RatingAndVotes([name])`\endlink
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_RatingAndVotes `ListItem.RatingAndVotes`\endlink
///     now available for albums/songs.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Mood`</b>,
///                  \anchor ListItem_Mood
///                  _string_,
///     @return The mood of the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Mood `ListItem.Mood`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Mpaa`</b>,
///                  \anchor ListItem_Mpaa
///                  _string_,
///     @return The MPAA rating of the currently selected movie in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ProgramCount`</b>,
///                  \anchor ListItem_ProgramCount
///                  _string_,
///     @return The number of times an xbe has been run from "my programs".
///     @todo description might be outdated
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Duration`</b>,
///                  \anchor ListItem_Duration
///                  _string_,
///     @return The duration of the currently selected item in a container
///     in the format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link ListItem_Duration `ListItem.Duration`\endlink will
///     return <b>hh:mm:ss</b> instead of the duration in minutes.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Duration(format)`</b>,
///                  \anchor ListItem_Duration_format
///                  _string_,
///     @return The duration of the currently selected item in a container in
///     different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.DBTYPE`</b>,
///                  \anchor ListItem_DBTYPE
///                  _string_,
///     @return The database type of the \ref ListItem_DBID "ListItem.DBID" for videos (movie\, set\,
///     genre\, actor\, tvshow\, season\, episode). It does not return any value
///     for the music library.
///     @note Beware with season\, the "*all seasons" entry does
///     give a DBTYPE "season" and a DBID\, but you can't get the details of that
///     entry since it's a virtual entry in the Video Library.
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_DBTYPE `ListItem.DBTYPE`\endlink
///     now available in the music library.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.DBID`</b>,
///                  \anchor ListItem_DBID
///                  _string_,
///     @return The database id of the currently selected listitem in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Appearances`</b>,
///                  \anchor ListItem_Appearances
///                  _string_,
///     @return The number of movies featuring the selected actor / directed by the selected director.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Appearances `ListItem.Appearances`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Cast`</b>,
///                  \anchor ListItem_Cast
///                  _string_,
///     @return A list of cast members\, separated by carriage returns.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link ListItem_Cast `ListItem.Cast`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Cast(separator)`</b>,
///                  \anchor ListItem_Cast_separator
///                  _string_,
///     @return A list of cast members\, separated by given separator\, or if no separator was
///     given separated by carriage returns.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_Cast_separator `ListItem.Cast(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.CastAndRole`</b>,
///                  \anchor ListItem_CastAndRole
///                  _string_,
///     @return A list of cast members and roles\, separated by carriage
///     returns. Every cast/role combination is formatted 'cast' as 'role' where 'as' is localised.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.CastAndRole(separator)`</b>,
///                  \anchor ListItem_CastAndRole_separator
///                  _string_,
///     @return A list of cast members and roles\, separated by given separator\, or if no separator
///     was given separated by carriage returns.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_CastAndRole_separator `ListItem.CastAndRole(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Studio`</b>,
///                  \anchor ListItem_Studio
///                  _string_,
///     @return The studio of current selected Music Video in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Top250`</b>,
///                  \anchor ListItem_Top250
///                  _string_,
///     @return The IMDb top250 position of the currently selected listitem in a
///     container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Trailer`</b>,
///                  \anchor ListItem_Trailer
///                  _string_,
///     @return The full trailer path with filename of the currently selected
///     movie in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Writer`</b>,
///                  \anchor ListItem_Writer
///                  _string_,
///     @return The name of Writer of current Video in a container.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link ListItem_Writer `ListItem.Writer`\endlink
///     also supports EPG.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Writer(separator)`</b>,
///                  \anchor ListItem_Writer_separator
///                  _string_,
///     @return A list of writers\, separated by given separator\, or if no separator was given
///     separated by the advanced settings value \“itemseparator\” for video items.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_Writer_separator `ListItem.Writer(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Tag`</b>,
///                  \anchor ListItem_Tag
///                  _string_,
///     @return The summary of current Video in a container.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Tag `ListItem.Tag`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Tagline`</b>,
///                  \anchor ListItem_Tagline
///                  _string_,
///     @return A Small Summary of current Video in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PlotOutline`</b>,
///                  \anchor ListItem_PlotOutline
///                  _string_,
///     @return A small Summary of current Video in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Plot`</b>,
///                  \anchor ListItem_Plot
///                  _string_,
///     @return The complete Text Summary of Video in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IMDBNumber`</b>,
///                  \anchor ListItem_IMDBNumber
///                  _string_,
///     @return The IMDb ID of the selected Video in a container.
///     <p><hr>
///     @skinning_v15 **[New Infolabel]** \link ListItem_IMDBNumber `ListItem.IMDBNumber`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.EpisodeName`</b>,
///                  \anchor ListItem_EpisodeName
///                  _string_,
///     @return The name of the episode if the selected EPG item is a TV Show (PVR).
///     <p><hr>
///     @skinning_v15 **[New Infolabel]** \link ListItem_EpisodeName `ListItem.EpisodeName`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PercentPlayed`</b>,
///                  \anchor ListItem_PercentPlayed
///                  _string_,
///     @return The percentage value [0-100] of how far the selected video has been
///     played.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.LastPlayed`</b>,
///                  \anchor ListItem_LastPlayed
///                  _string_,
///     @return The last play date of Video in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PlayCount`</b>,
///                  \anchor ListItem_PlayCount
///                  _string_,
///     @return The playcount of Video in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ChannelName`</b>,
///                  \anchor ListItem_ChannelName
///                  _string_,
///     @return The name of current selected TV channel in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ChannelLogo`</b>,
///                  \anchor ListItem_ChannelLogo
///                  _string_,
///     @return The path for the logo of the currently selected radio or TV channel\, if available (PVR).
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_ChannelLogo `ListItem.ChannelLogo`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.VideoCodec`</b>,
///                  \anchor ListItem_VideoCodec
///                  _string_,
///     @return The video codec of the currently selected video. Common values:
///      - <b>3iv2</b>
///      - <b>av1</b>
///      - <b>avc1</b>
///      - <b>div2</b>
///      - <b>div3</b>
///      - <b>divx</b>
///      - <b>divx 4</b>
///      - <b>dx50</b>
///      - <b>flv</b>
///      - <b>h264</b>
///      - <b>microsoft</b>
///      - <b>mp42</b>
///      - <b>mp43</b>
///      - <b>mp4v</b>
///      - <b>mpeg1video</b>
///      - <b>mpeg2video</b>
///      - <b>mpg4</b>
///      - <b>rv40</b>
///      - <b>svq1</b>
///      - <b>svq3</b>
///      - <b>theora</b>
///      - <b>vp6f</b>
///      - <b>wmv2</b>
///      - <b>wmv3</b>
///      - <b>wvc1</b>
///      - <b>xvid</b>
///      - etc
///     <p>
///   }
///   \table_row3{   <b>`ListItem.VideoResolution`</b>,
///                  \anchor ListItem_VideoResolution
///                  _string_,
///     @return The resolution of the currently selected video. Possible values:
///       - <b>480</b>
///       - <b>576</b>
///       - <b>540</b>
///       - <b>720</b>
///       - <b>1080</b>
///       - <b>4K</b>
///       - <b>8K</b>
///     @note 540 usually means a widescreen
///     format (around 960x540) while 576 means PAL resolutions (normally
///     720x576)\, therefore 540 is actually better resolution than 576.
///     <p><hr>
///     @skinning_v18 **[Updated Infolabel]** \link ListItem_VideoResolution ListItem.VideoResolution\endlink
///     added <b>8K</b> as a possible value.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.VideoAspect`</b>,
///                  \anchor ListItem_VideoAspect
///                  _string_,
///     @return The aspect ratio of the currently selected video. Possible values:
///      - <b>1.00</b>
///      - <b>1.19</b>
///      - <b>1.33</b>
///      - <b>1.37</b>
///      - <b>1.43</b>
///      - <b>1.50</b>
///      - <b>1.66</b>
///      - <b>1.78</b>
///      - <b>1.85</b>
///      - <b>1.90</b>
///      - <b>2.00</b>
///      - <b>2.20</b>
///      - <b>2.35</b>
///      - <b>2.40</b>
///      - <b>2.55</b>
///      - <b>2.76</b>
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AudioCodec`</b>,
///                  \anchor ListItem_AudioCodec
///                  _string_,
///     @return The audio codec of the currently selected video. Common values:
///       - <b>aac</b>
///       - <b>aac_lc</b>
///       - <b>he_aac</b>
///       - <b>he_aac_v2</b>
///       - <b>aac_ssr</b>
///       - <b>aac_ltp</b>
///       - <b>ac3</b>
///       - <b>cook</b>
///       - <b>dts</b>
///       - <b>dts_96_24</b>
///       - <b>dts_es</b>
///       - <b>dts_express</b>
///       - <b>dtshd_hra</b>
///       - <b>dtshd_ma</b>
///       - <b>dtshd_ma_x</b>
///       - <b>dtshd_ma_x_imax</b>
///       - <b>eac3</b>
///       - <b>eac3_ddp_atmos</b>
///       - <b>mp1</b>
///       - <b>mp2</b>
///       - <b>mp3</b>
///       - <b>pcm_s16be</b>
///       - <b>pcm_s16le</b>
///       - <b>pcm_u8</b>
///       - <b>truehd</b>
///       - <b>truehd_atmos</b>
///       - <b>vorbis</b>
///       - <b>wmapro</b>
///       - <b>wmav2</b>
///
///     The names are based on ffmpeg codec names with exceptions for specific codec profiles.
///     <p><hr>
///     @skinning_v22 **[Infolabel Updated]** \link ListItem_AudioCodec `ListItem.AudioCodec`\endlink
///     added aac_lc\, he_aac\, he_aac_v2\, aac_ssr\, aac_ltp\, dts_96_24\, dts_es\, dts_express\,
///     dtshd_ma_x\, dtshd_ma_x_imax\, eac3_ddp_atmos\, truehd_atmos
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AudioChannels(format)`</b>,
///                  \anchor ListItem_AudioChannels
///                  _string_,
///     @param format (optional) format of the infolabel. Possible values for the format:
///       - <b>(blank)</b> no format value: count of channels
///       - <b>defaultlayout</b> return a default channel layout in the format x.y.z for the
///         channel count (x=listener level speakers\, y=lfe channels\, z=overhead channels).
///         If a default layout is not defined for the channel count then the text "x channels" is
///         returned\, with x replaced by the channel count and "channels" localized to the user language.
///     @return The audio channel information of the currently selected video. Possible values
///       for the default format:
///       - <b>1</b>
///       - <b>2</b>
///       - <b>4</b>
///       - <b>5</b>
///       - <b>6</b>
///       - <b>8</b>
///       - <b>10</b>
///
///     Possible values for format "defaultlayout":
///       - <b>1.0</b>
///       - <b>2.0</b>
///       - <b>5.1</b>
///       - <b>6.1</b>
///       - <b>7.1</b>
///       - <b>9 channels</b>
///       - <b>9.1.6</b>
///
///     <p><hr>
///     @skinning_v16 **[Infolabel Updated]** \link ListItem_AudioChannels `ListItem.AudioChannels`\endlink
///     if a video contains no audio\, these infolabels will now return empty.
///     (they used to return 0)
///
///     @skinning_v22 **[Infolabel Updated]** \link ListItem_AudioChannels `ListItem.AudioChannels`\endlink
///     added optional format parameter
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AudioLanguage`</b>,
///                  \anchor ListItem_AudioLanguage
///                  _string_,
///     @return The audio language of the currently selected video (an
///     ISO 639-2 three character code: e.g. eng\, epo\, deu)
///     <p>
///   }
///   \table_row3{   <b>`ListItem.SubtitleLanguage`</b>,
///                  \anchor ListItem_SubtitleLanguage
///                  _string_,
///     @return The subtitle language of the currently selected video (an
///     ISO 639-2 three character code: e.g. eng\, epo\, deu)
///     <p>
///   }
///   \table_row3{   <b>`ListItem.FirstAudioLanguage`</b>,
///                  \anchor ListItem_FirstAudioLanguage
///                  _string_,
///     @return The language of the first audio stream of the currently selected video\, in the
///     order the source lists them. Usually an ISO 639-2 code taken from the container and
///     truncated to three characters\, but it is not validated as one\, and may be a BCP 47
///     derived code where the track title carries one
///     @note Unlike \link ListItem_AudioLanguage `ListItem.AudioLanguage`\endlink this is the
///     stream listed first by whatever produced the stream details: a bluray playlist\, whose
///     streams are in stream number order so the first is the one the disc expects a player to
///     start with; any other container\, in the order its demuxer reports; or an NFO\, in the
///     order its elements appear. It is not the stream playback will select.
///     Stream flags\, a choice remembered from a previous watch and the audio layout at play time
///     all affect the latter and are not available here.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_FirstAudioLanguage `ListItem.FirstAudioLanguage`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.FirstSubtitleLanguage`</b>,
///                  \anchor ListItem_FirstSubtitleLanguage
///                  _string_,
///     @return The language of the first subtitle stream of the currently selected video\, in
///     the order the source lists them\, with the same caveats as
///     \link ListItem_FirstAudioLanguage `ListItem.FirstAudioLanguage`\endlink
///     @note The counterpart of
///     \link ListItem_FirstAudioLanguage `ListItem.FirstAudioLanguage`\endlink for subtitles.
///     This says nothing about whether subtitles are displayed to begin with.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_FirstSubtitleLanguage `ListItem.FirstSubtitleLanguage`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.FirstAudioCodec`</b>,
///                  \anchor ListItem_FirstAudioCodec
///                  _string_,
///     @return The codec of the first audio stream of the currently selected video, in the order
///     the source lists them.
///     @note Unlike \link ListItem_AudioCodec `ListItem.AudioCodec`\endlink this describes the
///     stream listed first by the source\ as described for
///     \link ListItem_FirstAudioLanguage `ListItem.FirstAudioLanguage`\endlink\ rather than the
///     stream playback will select. Pairs
///     with \link ListItem_FirstAudioLanguage `ListItem.FirstAudioLanguage`\endlink.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_FirstAudioCodec `ListItem.FirstAudioCodec`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.FirstAudioChannels`</b>,
///                  \anchor ListItem_FirstAudioChannels
///                  _string_,
///     @return The number of audio channels of the first audio stream of the currently selected
///     video, in the order the source lists them.
///     @note Unlike \link ListItem_AudioChannels `ListItem.AudioChannels`\endlink this describes
///     the stream listed first by the source\ as described for
///     \link ListItem_FirstAudioLanguage `ListItem.FirstAudioLanguage`\endlink. Accepts
///     the same `DefaultLayout` parameter\, ie. `ListItem.FirstAudioChannels(DefaultLayout)`
///     renders 6 as 5.1. Pairs with
///     \link ListItem_FirstAudioLanguage `ListItem.FirstAudioLanguage`\endlink.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_FirstAudioChannels `ListItem.FirstAudioChannels`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(AudioCodec.[n])`</b>,
///                  \anchor ListItem_Property_AudioCodec
///                  _string_,
///     @return The audio codec of the currently selected video
///     @param n - the number of the audiostream (values: see \ref ListItem_AudioCodec "ListItem.AudioCodec")
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link ListItem_Property_AudioCodec `ListItem.Property(AudioCodec.[n])`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(AudioChannels.[n])`</b>,
///                  \anchor ListItem_Property_AudioChannels
///                  _string_,
///     @return The number of audio channels of the currently selected video
///     @param n - the number of the audiostream (values: see
///     \ref ListItem_AudioChannels "ListItem.AudioChannels")
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link ListItem_Property_AudioChannels `ListItem.Property(AudioChannels.[n])`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(AudioLanguage.[n])`</b>,
///                  \anchor ListItem_Property_AudioLanguage
///                  _string_,
///     @return The audio language of the currently selected video
///     @param n - the number of the audiostream (values: see \ref ListItem_AudioLanguage "ListItem.AudioLanguage")
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link ListItem_Property_AudioLanguage `ListItem.Property(AudioLanguage.[n])`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(SubtitleLanguage.[n])`</b>,
///                  \anchor ListItem_Property_SubtitleLanguage
///                  _string_,
///     @return The subtitle language of the currently selected video
///     @param n - the number of the subtitle (values: see \ref ListItem_SubtitleLanguage "ListItem.SubtitleLanguage")
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link ListItem_Property_SubtitleLanguage `ListItem.Property(SubtitleLanguage.[n])`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.Disclaimer)`</b>,
///                  \anchor ListItem_Property_AddonDisclaimer
///                  _string_,
///     @return The disclaimer of the currently selected addon.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.Changelog)`</b>,
///                  \anchor ListItem_Property_AddonChangelog
///                  _string_,
///     @return The changelog of the currently selected addon.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.ID)`</b>,
///                  \anchor ListItem_Property_AddonID
///                  _string_,
///     @return The identifier of the currently selected addon.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.Status)`</b>,
///                  \anchor ListItem_Property_AddonStatus
///                  _string_,
///     @return The status of the currently selected addon.
///     @todo missing reference in GuiInfoManager.cpp making it hard to track.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.Orphaned)`</b>,
///                  \anchor ListItem_Property_AddonOrphaned
///                  _boolean_,
///     @return **True** if the Addon is orphanad.
///     @todo missing reference in GuiInfoManager.cpp making it hard to track.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link ListItem_Property_AddonOrphaned `ListItem.Property(Addon.Orphaned)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Addon.Path)`</b>,
///                  \anchor ListItem_Property_AddonPath
///                  _string_,
///     @return The path of the currently selected addon.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.StartTime`</b>,
///                  \anchor ListItem_StartTime
///                  _string_,
///     @return The start time of current selected TV programme in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.EndTime`</b>,
///                  \anchor ListItem_EndTime
///                  _string_,
///     @return The end time of current selected TV programme in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.StartDate`</b>,
///                  \anchor ListItem_StartDate
///                  _string_,
///     @return The start date of current selected TV programme in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.EndDate`</b>,
///                  \anchor ListItem_EndDate
///                  _string_,
///     @return The end date of current selected TV programme in a container.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextTitle`</b>,
///                  \anchor ListItem_NextTitle
///                  _string_,
///     @return The title of the next item (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextGenre`</b>,
///                  \anchor ListItem_NextGenre
///                  _string_,
///     @return The genre of the next item (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextGenre(separator)`</b>,
///                  \anchor ListItem_NextGenre_separator
///                  _string_,
///     @return A list of genres of the the next item (PVR)\, separated by given separator\, or if
///     no separator was given separated by the advanced settings value \“itemseparator\” for
///     videos.
///     Possible values for separator: comma\, pipe\, slash\, cr\, dash\, colon\, semicolon\, fullstop
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_NextGenre_separator `ListItem.NextGenre(separator)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextPlot`</b>,
///                  \anchor ListItem_NextPlot
///                  _string_,
///     @return The plot of the next item (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextPlotOutline`</b>,
///                  \anchor ListItem_NextPlotOutline
///                  _string_,
///     @return The plot outline of the next item (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextStartTime`</b>,
///                  \anchor ListItem_NextStartTime
///                  _string_,
///     @return The start time of the next item (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextEndTime`</b>,
///                  \anchor ListItem_NextEndTime
///                  _string_,
///     @return The end of the next item (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextStartDate`</b>,
///                  \anchor ListItem_NextStartDate
///                  _string_,
///     @return The start date of the next item (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextEndDate`</b>,
///                  \anchor ListItem_NextEndDate
///                  _string_,
///     @return The end date of the next item (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextDuration`</b>,
///                  \anchor ListItem_NextDuration
///                  _string_,
///     @return The duration of the next item (PVR) in the format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_NextDuration `ListItem.NextDuration`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.NextDuration(format)`</b>,
///                  \anchor ListItem_NextDuration_format
///                  _string_,
///     @return The duration of the next item (PVR) in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_NextDuration_format `ListItem.NextDuration(format)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ChannelGroup`</b>,
///                  \anchor ListItem_ChannelGroup
///                  _string_,
///     @return The channel group of the selected item (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ChannelNumberLabel`</b>,
///                  \anchor ListItem_ChannelNumberLabel
///                  _string_,
///     @return The channel and subchannel number of the currently selected channel that's
///     currently playing (PVR).
///     <p><hr>
///     @skinning_v14 **[New Infolabel]** \link ListItem_ChannelNumberLabel `ListItem.ChannelNumberLabel`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Progress`</b>,
///                  \anchor ListItem_Progress
///                  _string_,
///     @return The part of the programme that's been played (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.StereoscopicMode`</b>,
///                  \anchor ListItem_StereoscopicMode
///                  _string_,
///     @return The stereomode of the selected video:
///       - <b>mono</b>
///       - <b>split_vertical</b>
///       - <b>split_horizontal</b>
///       - <b>row_interleaved</b>
///       - <b>anaglyph_cyan_red</b>
///       - <b>anaglyph_green_magenta</b>
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link ListItem_StereoscopicMode `ListItem.StereoscopicMode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.HasTimerSchedule`</b>,
///                  \anchor ListItem_HasTimerSchedule
///                  _boolean_,
///     @return **True** if the item was scheduled by a timer rule (PVR).
///     <p><hr>
///     @skinning_v16 **[New Boolean Condition]** \ref ListItem_HasTimerSchedule "ListItem.HasTimerSchedule"
///     <p>
///   }
///   \table_row3{   <b>`ListItem.HasReminder`</b>,
///                  \anchor ListItem_HasReminder
///                  _boolean_,
///     @return **True** if the item has a reminder set (PVR).
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \ref ListItem_HasReminder "ListItem.HasReminder"
///     <p>
///   }
///   \table_row3{   <b>`ListItem.HasReminderRule`</b>,
///                  \anchor ListItem_HasReminderRule
///                  _boolean_,
///     @return **True** if the item was scheduled by a reminder timer rule (PVR).
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \ref ListItem_HasReminderRule "ListItem.HasReminderRule"
///     <p>
///   }
///   \table_row3{   <b>`ListItem.HasRecording`</b>,
///                  \anchor ListItem_HasRecording
///                  _boolean_,
///     @return **True** if a given epg tag item currently gets recorded or has been recorded.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.TimerHasError`</b>,
///                  \anchor ListItem_TimerHasError
///                  _boolean_,
///     @return **True** if the item has a timer and it won't be recorded because of an error (PVR).
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \ref ListItem_TimerHasError "ListItem.TimerHasError"
///     <p>
///   }
///   \table_row3{   <b>`ListItem.TimerHasConflict`</b>,
///                  \anchor ListItem_TimerHasConflict
///                  _boolean_,
///     @return **True** if the item has a timer and it won't be recorded because of a conflict (PVR).
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \ref ListItem_TimerHasConflict "ListItem.TimerHasConflict"
///     <p>
///   }
///   \table_row3{   <b>`ListItem.TimerIsActive`</b>,
///                  \anchor ListItem_TimerIsActive
///                  _boolean_,
///     @return **True** if the item has a timer that will be recorded\, i.e. the timer is enabled (PVR).
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \ref ListItem_TimerIsActive "ListItem.TimerIsActive"
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Comment`</b>,
///                  \anchor ListItem_Comment
///                  _string_,
///     @return The comment assigned to the item (PVR/MUSIC).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.TimerType`</b>,
///                  \anchor ListItem_TimerType
///                  _string_,
///     @return The type of the PVR timer / timer rule item as a human readable string.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.EpgEventTitle`</b>,
///                  \anchor ListItem_EpgEventTitle
///                  _string_,
///     @return The title of the epg event associated with the item\, if any.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.EpgEventIcon`</b>,
///                  \anchor ListItem_EpgEventIcon
///                  _string_,
///     @return The thumbnail for the EPG event associated with the item (if it exists).
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_EpgEventIcon `ListItem.EpgEventIcon`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.InProgress`</b>,
///                  \anchor ListItem_InProgress
///                  _boolean_,
///     @return **True** if the EPG event item is currently active (time-wise).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsParentFolder`</b>,
///                  \anchor ListItem_IsParentFolder
///                  _boolean_,
///     @return **True** if the current list item is the goto parent folder '..'.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link ListItem_IsParentFolder `ListItem.IsParentFolder`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonName`</b>,
///                  \anchor ListItem_AddonName
///                  _string_,
///     @return The name of the currently selected addon.
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonName `ListItem.AddonName`\endlink
///     replaces `ListItem.Property(Addon.Name)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonVersion`</b>,
///                  \anchor ListItem_AddonVersion
///                  _string_,
///     @return The version of the currently selected addon.
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonVersion `ListItem.AddonVersion`\endlink
///     replaces `ListItem.Property(Addon.Version)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonCreator`</b>,
///                  \anchor ListItem_AddonCreator
///                  _string_,
///     @return The name of the author the currently selected addon.
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonCreator `ListItem.AddonCreator`\endlink
///     replaces `ListItem.Property(Addon.Creator)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonSummary`</b>,
///                  \anchor ListItem_AddonSummary
///                  _string_,
///     @return A short description of the currently selected addon.
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonSummary `ListItem.AddonSummary`\endlink
///     replaces `ListItem.Property(Addon.Summary)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonDescription`</b>,
///                  \anchor ListItem_AddonDescription
///                  _string_,
///     @return The full description of the currently selected addon.
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonDescription `ListItem.AddonDescription`\endlink
///     replaces `ListItem.Property(Addon.Description)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonDisclaimer`</b>,
///                  \anchor ListItem_AddonDisclaimer
///                  _string_,
///     @return The disclaimer of the currently selected addon.
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonDisclaimer `ListItem.AddonDisclaimer`\endlink
///     replaces `ListItem.Property(Addon.Disclaimer)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonBroken`</b>,
///                  \anchor ListItem_AddonBroken
///                  _string_,
///     @return A message when the addon is marked as broken in the repo.
///     @deprecated but still available\, use \ref ListItem_AddonLifecycleDesc "ListItem.AddonLifecycleDesc"
///     instead
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonBroken `ListItem.AddonBroken`\endlink
///     replaces `ListItem.Property(Addon.Broken)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonLifecycleType`</b>,
///                  \anchor ListItem_AddonLifecycleType
///                  _string_,
///     @return String name when the addon is marked as special condition in the repo.
///       - <b>Label: 24169 (Normal)</b> - Used if an add-on has no special lifecycle state which is the default state
///       - <b>Label: 24170 (Deprecated)</b> - The add-on should be marked as deprecated but is still usable
///       - <b>Label: 24171 (Broken)</b> - The add-on should marked as broken in the repository
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_AddonLifecycleType `ListItem.AddonLifecycleType`\endlink
///     replaces `ListItem.AddonBroken`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonLifecycleDesc`</b>,
///                  \anchor ListItem_AddonLifecycleDesc
///                  _string_,
///     @return From addon defined message text when it is marked as special condition inside repository.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_AddonLifecycleDesc `ListItem.AddonLifecycleDesc`\endlink
///     replaces `ListItem.AddonBroken`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonType`</b>,
///                  \anchor ListItem_AddonType
///                  _string_,
///     @return The type (screensaver\, script\, skin\, etc...) of the currently selected addon.
///     <p><hr>
///     @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonType `ListItem.AddonType`\endlink
///     replaces `ListItem.Property(Addon.Type)`.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonInstallDate`</b>,
///                  \anchor ListItem_AddonInstallDate
///                  _string_,
///     @return The date the addon was installed.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_AddonInstallDate `ListItem.AddonInstallDate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonLastUpdated`</b>,
///                  \anchor ListItem_AddonLastUpdated
///                  _string_,
///     @return The date the addon was last updated.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_AddonLastUpdated `ListItem.AddonLastUpdated`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonLastUsed`</b>,
///                  \anchor ListItem_AddonLastUsed
///                  _string_,
///     @return The date the addon was used last.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_AddonLastUsed `ListItem.AddonLastUsed`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonNews`</b>,
///                  \anchor ListItem_AddonNews
///                  _string_,
///     @return A brief changelog\, taken from the addons' `addon.xml` file.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_AddonNews `ListItem.AddonNews`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonSize`</b>,
///                  \anchor ListItem_AddonSize
///                  _string_,
///     @return The filesize of the addon.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_AddonSize `ListItem.AddonSize`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AddonOrigin`</b>,
///                  \anchor ListItem_AddonOrigin
///                  _string_,
///     @return The name of the repository the add-on originates from.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ExpirationDate`</b>,
///                  \anchor ListItem_ExpirationDate
///                  _string_,
///     @return The expiration date of the selected item in a container\, empty string if not supported.
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ExpirationTime`</b>,
///                  \anchor ListItem_ExpirationTime
///                  _string_,
///     @return The expiration time of the selected item in a container\, empty string if not supported
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Art(type)`</b>,
///                  \anchor ListItem_Art_Type
///                  _string_,
///     @return A particular art type for an item.
///     @param type - the art type. It can be any value (set by scripts and scrappers). Common values:
///       - <b>clearart</b> - the clearart (if it exists) of the currently selected movie or tv show.
///       - <b>clearlogo</b> - the clearlogo (if it exists) of the currently selected movie or tv show.
///       - <b>landscape</b> - the 16:9 landscape (if it exists) of the currently selected item.
///       - <b>thumb</b> - the thumbnail of the currently selected item.
///       - <b>poster</b> - the poster of the currently selected movie or tv show.
///       - <b>banner</b> - the banner of the currently selected tv show.
///       - <b>fanart</b> - the fanart image of the currently selected item.
///       - <b>set.fanart</b> - the fanart image of the currently selected movieset.
///       - <b>tvshow.poster</b> - the tv show poster of the parent container.
///       - <b>tvshow.banner</b> - the tv show banner of the parent container.
///       - <b>tvshow.clearlogo</b> - the tv show clearlogo (if it exists) of the parent container.
///       - <b>tvshow.landscape</b> - the tv show landscape (if it exists) of the parent container.
///       - <b>tvshow.clearart</b> - the tv show clearart (if it exists) of the parent container.
///       - <b>season.poster</b> - the season poster of the currently selected season. (Only available in DialogVideoInfo.xml).
///       - <b>season.banner</b> - the season banner of the currently selected season. (Only available in DialogVideoInfo.xml).
///       - <b>season.fanart</b> - the fanart image of the currently selected season. (Only available in DialogVideoInfo.xml)
///       - <b>artist.thumb</b> - the artist thumb of an album or song item.
///       - <b>artist.fanart</b> - the artist fanart of an album or song item.
///       - <b>album.thumb</b> - the album thumb (cover) of a song item.
///       - <b>artist[n].*</b> - in case a song has multiple artists\, a digit is added to the art type for the 2nd artist onwards
/// e.g `Listitem.Art(artist1.thumb)` gives the thumb of the 2nd artist of a song.
///       - <b>albumartist[n].*</b> - n case a song has multiple album artists\, a digit is added to the art type for the 2nd artist
/// onwards e.g `Listitem.Art(artist1.thumb)` gives the thumb of the 2nd artist of a song.
///     <p>
///     @todo Find a better way of finding the art types instead of manually defining them here.
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link ListItem_Art_Type `ListItem.Art(type)`\endlink add <b>artist[n].*</b> and
///     <b>albumartist[n].*</b> as possible targets for <b>type</b>
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Platform`</b>,
///                  \anchor ListItem_Platform
///                  _string_,
///     @return The game platform (e.g. "Atari 2600") (RETROPLAYER).
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Platform `ListItem.Platform`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Genres`</b>,
///                  \anchor ListItem_Genres
///                  _string_,
///     @return The game genres (e.g. "["Action"\,"Strategy"]") (RETROPLAYER).
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Genres `ListItem.Genres`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Publisher`</b>,
///                  \anchor ListItem_Publisher
///                  _string_,
///     @return The game publisher (e.g. "Nintendo") (RETROPLAYER).
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Publisher `ListItem.Publisher`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Developer`</b>,
///                  \anchor ListItem_Developer
///                  _string_,
///     @return The game developer (e.g. "Square") (RETROPLAYER).
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Developer `ListItem.Developer`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Overview`</b>,
///                  \anchor ListItem_Overview
///                  _string_,
///     @return The game overview/summary (RETROPLAYER).
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Overview `ListItem.Overview`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.GameClient`</b>,
///                  \anchor ListItem_GameClient
///                  _string_,
///     @return The add-on ID of the game client (a.k.a. emulator) to use for playing the game
///     (e.g. game.libretro.fceumm) (RETROPLAYER).
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_GameClient `ListItem.GameClient`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(propname)`</b>,
///                  \anchor ListItem_Property_Propname
///                  _string_,
///     @return The requested property of a ListItem.
///     @param propname - the property requested
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Role.Composer)`</b>,
///                  \anchor ListItem_Property_Role_Composer
///                  _string_,
///     @return The name of the person who composed the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Composer `ListItem.Property(Role.Composer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Role.Conductor)`</b>,
///                  \anchor ListItem_Property_Role_Conductor
///                  _string_,
///     @return The name of the person who conducted the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Conductor `ListItem.Property(Role.Conductor)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Role.Orchestra)`</b>,
///                  \anchor ListItem_Property_Role_Orchestra
///                  _string_,
///     @return The name of the orchestra performing the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Orchestra `ListItem.Property(Role.Orchestra)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Role.Lyricist)`</b>,
///                  \anchor ListItem_Property_Role_Lyricist
///                  _string_,
///     @return The name of the person who wrote the lyrics of the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Lyricist `ListItem.Property(Role.Lyricist)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Role.Remixer)`</b>,
///                  \anchor ListItem_Property_Role_Remixer
///                  _string_,
///     @return The name of the person who remixed the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Remixer `ListItem.Property(Role.Remixer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Role.Arranger)`</b>,
///                  \anchor ListItem_Property_Role_Arranger
///                  _string_,
///     @return The name of the person who arranged the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Arranger `ListItem.Property(Role.Arranger)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Role.Engineer)`</b>,
///                  \anchor ListItem_Property_Role_Engineer
///                  _string_,
///     @return The name of the person who was the engineer of the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Engineer `ListItem.Property(Role.Engineer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Role.Producer)`</b>,
///                  \anchor ListItem_Property_Role_Producer
///                  _string_,
///     @return The name of the person who produced the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Producer `ListItem.Property(Role.Producer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Role.DJMixer)`</b>,
///                  \anchor ListItem_Property_Role_DJMixer
///                  _string_,
///     @return The name of the dj who remixed the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_DJMixer `ListItem.Property(Role.DJMixer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Role.Mixer)`</b>,
///                  \anchor ListItem_Property_Role_Mixer
///                  _string_,
///     @return The name of the person who mixed the selected song.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_DJMixer `ListItem.Property(Role.DJMixer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Game.VideoFilter)`</b>,
///                  \anchor ListItem_Property_Game_VideoFilter
///                  _string_,
///     @return The video filter of the list item representing a
///     gamewindow control (RETROPLAYER).
///     See \link RetroPlayer_VideoFilter RetroPlayer.VideoFilter \endlink
///     for the possible values.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Property_Game_VideoFilter `ListItem.Property(Game.VideoFilter)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Game.StretchMode)`</b>,
///                  \anchor ListItem_Property_Game_StretchMode
///                  _string_,
///     @return The stretch mode of the list item representing a
///     gamewindow control (RETROPLAYER).
///     See \link RetroPlayer_StretchMode RetroPlayer.StretchMode \endlink
///     for the possible values.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Property_Game_StretchMode `ListItem.Property(Game.StretchMode)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.Property(Game.VideoRotation)`</b>,
///                  \anchor ListItem_Property_Game_VideoRotation
///                  _integer_,
///     @return The video rotation of the list item representing a
///     gamewindow control (RETROPLAYER).
///     See \link RetroPlayer_VideoRotation RetroPlayer.VideoRotation \endlink
///     for the possible values.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link ListItem_Property_Game_VideoRotation `ListItem.Property(Game.VideoRotation)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ParentalRating`</b>,
///                  \anchor ListItem_ParentalRating
///                  _string_,
///     @return The parental rating of the list item (PVR).
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ParentalRatingCode`</b>,
///                  \anchor ListItem_ParentalRatingCode
///                  _string_,
///     @return The parental rating code (eg: 'PG'\, etc) of the list item (PVR).
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link ListItem_ParentalRatingCode `ListItem.ParentalRatingCode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ParentalRatingIcon`</b>,
///                  \anchor ListItem_ParentalRatingIcon
///                  _string_,
///     @return The parental rating icon path of the list item (PVR).
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_ParentalRatingIcon `ListItem.ParentalRatingIcon`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ParentalRatingSource`</b>,
///                  \anchor ListItem_ParentalRatingSource
///                  _string_,
///     @return The source used to determine the parental rating of the list item (PVR).
///     Values could include the Country alpha-3 code or the name/abbreviation
///     of the authority issuing the rating code.  Can be used with
///     the \link ListItem_ParentalRatingCode `ParentalRatingCode`\endlink for skin-derived icons if required.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_ParentalRatingSource `ListItem.ParentalRatingSource`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.CurrentItem`</b>,
///                  \anchor ListItem_CurrentItem
///                  _string_,
///     @return The current index of the item in a container starting at 1.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_CurrentItem `ListItem.CurrentItem`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsNew`</b>,
///                  \anchor ListItem_IsNew
///                  _boolean_,
///     @return **True** if the item is new (for example\, a Live TV show that will be first aired).
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_IsNew `ListItem.IsNew`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsPremiere`</b>,
///                  \anchor ListItem_IsPremiere
///                  _boolean_,
///     @return **True** if the item is a premiere (for example\, a Movie first showing or season first on Live TV).
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_IsPremiere `ListItem.IsPremiere`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsFinale`</b>,
///                  \anchor ListItem_IsFinale
///                  _boolean_,
///     @return **True** if the item is a finale (for example\, a season finale showing on Live TV).
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_IsFinale `ListItem.IsFinale`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsLive`</b>,
///                  \anchor ListItem_IsLive
///                  _boolean_,
///     @return **True** if the item is live (for example\, a Live TV sports event).
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_IsLive `ListItem.IsLive`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.DiscTitle`</b>,
///                  \anchor ListItem_DiscTitle
///                  _string_,
///     @return The disc title of the currently selected album or song.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_DiscTitle `ListItem.DiscTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.IsBoxset`</b>,
///                  \anchor ListItem_IsBoxset
///                  _boolean_,
///     @return **True** if the item is part of a boxset album.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_IsBoxset `ListItem.IsBoxset`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.TotalDiscs`</b>,
///                  \anchor ListItem_TotalDiscs
///                  _boolean_,
///     @return The total number of discs belonging to an album.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_TotalDiscs `ListItem.TotalDiscs`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.ReleaseDate`</b>,
///                  \anchor ListItem_ReleaseDate
///                  _string_,
///     @return The release date of the item.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_ReleaseDate `ListItem.ReleaseDate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.OriginalDate`</b>,
///                  \anchor ListItem_OriginalDate
///                  _string_,
///     @return The original release date of the item. Can be full or partial date.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_OriginalDate `ListItem.OriginalDate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.BPM`</b>,
///                  \anchor ListItem_BPM
///                  _string_,
///     @return The BPM of a song.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_BPM `ListItem.BPM`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.UniqueID(name)`</b>,
///                  \anchor ListItem_UniqueID
///                  _string_,
///     @return The scraped metadata id of the currently selected item in a container\,
///     for use in dialogvideoinfo.xml.
///     @param name - the name of the metadata provider.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_UniqueID `ListItem.UniqueID(name)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.BitRate`</b>,
///                  \anchor ListItem_BitRate
///                  _string_,
///     @return The bitrate of a song. Actual rate for CBR\, average rate for VBR.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_BitRate `ListItem.BitRate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.SampleRate`</b>,
///                  \anchor ListItem_SampleRate
///                  _string_,
///     @return The sample rate of a song / 1000.0 eg 44.1\, 48\, 96 etc.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_SampleRate `ListItem.SampleRate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.MusicChannels(format)`</b>,
///                  \anchor ListItem_MusicChannels
///                  _string_,
///     @param[in] format (optional) format of the infolabel.
///     (possible values: see \ref ListItem_AudioChannels "ListItem.AudioChannels").
///     @return The number of audio channels of a song.
///     (possible values: see \ref ListItem_AudioChannels "ListItem.AudioChannels").
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_MusicChannels `ListItem.MusicChannels`\endlink
///
///     @skinning_v22 **[Infolabel Updated]** \link ListItem_MusicChannels `ListItem.MusicChannels`\endlink
///     added optional format parameter
///     <p>
///   }
///   \table_row3{   <b>`ListItem.TvShowDBID`</b>,
///                  \anchor ListItem_TvShowDBID
///                  _string_,
///     @return The database id of the TvShow for the currently selected Season or Episode.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_TvShowDBID `ListItem.TvShowDBID`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.AlbumStatus`</b>,
///                  \anchor ListItem_AlbumStatus
///                  _string_,
///     @return The Musicbrainz release status of the album (official\, bootleg\, promotion etc)
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link ListItem_AlbumStatus `ListItem.AlbumStatus`\endlink
///   }
///   \table_row3{   <b>`ListItem.HdrType`</b>,
///                  \anchor ListItem_HdrType
///                  _string_,
///     @return String containing the name of the detected HDR type or empty if not HDR. See \ref StreamHdrType for the list of possible values.
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link ListItem_HdrType `ListItem.HdrType`\endlink
///   }
///   \table_row3{   <b>`ListItem.Property(HdrType.[n])`</b>,
///                  \anchor ListItem_Property_HdrType
///                  _string_,
///     @return The HDR type of the numbered stream of the currently selected video or empty if not HDR. See \ref StreamHdrType for the list of possible values.
///     @param n - the number of the videostream.
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link ListItem_Property_HdrType `ListItem.Property(HdrType.[n])`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.HdrDetail`</b>,
///                  \anchor ListItem_HdrDetail
///                  _string_,
///     @return String containing details for the HDR type (currently only for DV - profile and EL type) or empty if not HDR. Prints eg 5\, 7FEL\,
///     and compatibility ID for profile 8 eg 8.4.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_HdrDetail `ListItem.HdrDetail`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.SongVideoURL`</b>,
///                  \anchor ListItem_SongVideoURL
///                  _string_,
///     @return Link to a video of a song
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link ListItem_SongVideoURL `ListItem.SongVideoURL`\endlink
///   }
///   \table_row3{   <b>`ListItem.VideoWidth`</b>,
///                  \anchor ListItem_VideoWidth
///                  _string_,
///     @return String containing width of video in pixels - empty if unknown.
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link ListItem_VideoWidth `ListItem.VideoWidth`\endlink
///   }
///   \table_row3{   <b>`ListItem.VideoHeight`</b>,
///                  \anchor ListItem_VideoHeight
///                  _string_,
///     @return String containing height of video in pixels - empty if unknown.
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link ListItem_VideoHeight `ListItem.VideoHeight`\endlink
///   }
///   \table_row3{   <b>`ListItem.HasVideoVersions`</b>,
///                  \anchor ListItem_HasVideoVersions
///                  _boolean_,
///     @return **True** when the selected item has multiple video versions.
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link ListItem_HasVideoVersions `ListItem.HasVideoVersions`\endlink
///   }
///   \table_row3{   <b>`ListItem.IsVideoExtra`</b>,
///                  \anchor ListItem_IsVideoExtra
///                  _boolean_,
///     @return **True** when the selected item is a video extra.
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link ListItem_IsVideoExtra `ListItem.IsVideoExtra`\endlink
///   }
///   \table_row3{   <b>`ListItem.VideoVersionName`</b>,
///                  \anchor ListItem_VideoVersionName
///                  _string_,
///     @return String containing the name of the version of a video - empty for extras or if no version available
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link ListItem_VideoVersionName `ListItem.VideoVersionName`\endlink
///   }
///   \table_row3{   <b>`ListItem.HasVideoExtras`</b>,
///                  \anchor ListItem_HasVideoExtras
///                  _boolean_,
///     @return **True** when the selected item has video extras.
///     <p><hr>
///     @skinning_v21 **[New Infolabel]** \link ListItem_HasVideoExtras `ListItem.HasVideoExtras`\endlink
///   }
///   \table_row3{   <b>`ListItem.PVRClientName`</b>,
///                  \anchor ListItem_PVRClientName
///                  _string_,
///     @return If selected item is of type PVR (recording\, timer\, EPG)\, the name of the PVR client
///     add-on\, as specified by the add-on developer. Empty if the item is not of type PVR.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_PVRClientName `ListItem.PVRClientName`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PVRInstanceName`</b>,
///                  \anchor ListItem_PVRInstanceName
///                  _string_,
///     @return If selected item is of type PVR (recording\, timer\, EPG)\, the name of the instance
///     of the PVR client add-on\, as specified by the user in the add-on settings. Empty if the
///     PVR client add-on does not support multiple instances or item is not of type PVR.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_PVRInstanceName `ListItem.PVRInstanceName`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.PVRGroupOrigin`</b>,
///                  \anchor ListItem_PVRGroupOrigin
///                  _string_,
///     @return If selected item is of type PVR channel group\, the creator (user\, system\, client) of
///     the group.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_PVRGroupOrigin `ListItem.PVRGroupOrigin`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.EpisodePart`</b>,
///                  \anchor ListItem_EpisodePart
///                  _string_,
///     @return string containing the number of parts of a single episode - empty if no data provided
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_EpisodePart `ListItem.EpisodePart`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.MediaProviders`</b>,
///                  \anchor ListItem_MediaProviders
///                  _string_,
///     @return string containing the names of the media providers of the item\, separated by commas if multiple are present.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_MediaProviders `ListItem.MediaProviders`\endlink
///     <p>
///   }
///   \table_row3{   <b>`ListItem.TitleExtraInfo`</b>,
///                  \anchor ListItem_TitleExtraInfo
///                  _string_,
///     @return string containing extra information\, enriching the title of the item.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link ListItem_TitleExtraInfo `ListItem.TitleExtraInfo`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 232> listitem_labels = {{
    {"thumb",                         LISTITEM_THUMB},
    {"icon",                          LISTITEM_ICON},
    {"actualicon",                    LISTITEM_ACTUAL_ICON},
    {"overlay",                       LISTITEM_OVERLAY},
    {"label",                         LISTITEM_LABEL},
    {"label2",                        LISTITEM_LABEL2},
    {"title",                         LISTITEM_TITLE},
    {"tracknumber",                   LISTITEM_TRACKNUMBER},
    {"artist",                        LISTITEM_ARTIST},
    {"album",                         LISTITEM_ALBUM},
    {"albumartist",                   LISTITEM_ALBUM_ARTIST},
    {"year",                          LISTITEM_YEAR},
    {"genre",                         LISTITEM_GENRE},
    {"contributors",                  LISTITEM_CONTRIBUTORS},
    {"contributorandrole",            LISTITEM_CONTRIBUTOR_AND_ROLE},
    {"director",                      LISTITEM_DIRECTOR},
    {"disctitle",                     LISTITEM_DISC_TITLE},
    {"filename",                      LISTITEM_FILENAME},
    {"filenameandpath",               LISTITEM_FILENAME_AND_PATH},
    {"decodedfilenameandpath",        LISTITEM_DECODED_FILENAME_AND_PATH},
    {"fileextension",                 LISTITEM_FILE_EXTENSION},
    {"filenamenoextension",           LISTITEM_FILENAME_NO_EXTENSION},
    {"date",                          LISTITEM_DATE},
    {"datetime",                      LISTITEM_DATETIME},
    {"size",                          LISTITEM_SIZE},
    {"rating",                        LISTITEM_RATING},
    {"ratingandvotes",                LISTITEM_RATING_AND_VOTES},
    {"userrating",                    LISTITEM_USER_RATING},
    {"votes",                         LISTITEM_VOTES},
    {"mood",                          LISTITEM_MOOD},
    {"programcount",                  LISTITEM_PROGRAM_COUNT},
    {"duration",                      LISTITEM_DURATION},
    {"isselected",                    LISTITEM_ISSELECTED},
    {"isplaying",                     LISTITEM_ISPLAYING},
    {"plot",                          LISTITEM_PLOT},
    {"plotoutline",                   LISTITEM_PLOT_OUTLINE},
    {"episode",                       LISTITEM_EPISODE},
    {"season",                        LISTITEM_SEASON},
    {"tvshowtitle",                   LISTITEM_TVSHOW},
    {"premiered",                     LISTITEM_PREMIERED},
    {"comment",                       LISTITEM_COMMENT},
    {"path",                          LISTITEM_PATH},
    {"foldername",                    LISTITEM_FOLDERNAME},
    {"folderpath",                    LISTITEM_FOLDERPATH},
    {"picturepath",                   LISTITEM_PICTURE_PATH},
    {"pictureresolution",             LISTITEM_PICTURE_RESOLUTION},
    {"picturedatetime",               LISTITEM_PICTURE_DATETIME},
    {"picturedate",                   LISTITEM_PICTURE_DATE},
    {"picturelongdatetime",           LISTITEM_PICTURE_LONGDATETIME},
    {"picturelongdate",               LISTITEM_PICTURE_LONGDATE},
    {"picturecomment",                LISTITEM_PICTURE_COMMENT},
    {"picturecaption",                LISTITEM_PICTURE_CAPTION},
    {"picturedesc",                   LISTITEM_PICTURE_DESC},
    {"picturekeywords",               LISTITEM_PICTURE_KEYWORDS},
    {"picturecammake",                LISTITEM_PICTURE_CAM_MAKE},
    {"picturecammodel",               LISTITEM_PICTURE_CAM_MODEL},
    {"pictureaperture",               LISTITEM_PICTURE_APERTURE},
    {"picturefocallen",               LISTITEM_PICTURE_FOCAL_LEN},
    {"picturefocusdist",              LISTITEM_PICTURE_FOCUS_DIST},
    {"pictureexpmode",                LISTITEM_PICTURE_EXP_MODE},
    {"pictureexptime",                LISTITEM_PICTURE_EXP_TIME},
    {"pictureiso",                    LISTITEM_PICTURE_ISO},
    {"pictureauthor",                 LISTITEM_PICTURE_AUTHOR},
    {"picturebyline",                 LISTITEM_PICTURE_BYLINE},
    {"picturebylinetitle",            LISTITEM_PICTURE_BYLINE_TITLE},
    {"picturecategory",               LISTITEM_PICTURE_CATEGORY},
    {"pictureccdwidth",               LISTITEM_PICTURE_CCD_WIDTH},
    {"picturecity",                   LISTITEM_PICTURE_CITY},
    {"pictureurgency",                LISTITEM_PICTURE_URGENCY},
    {"picturecopyrightnotice",        LISTITEM_PICTURE_COPYRIGHT_NOTICE},
    {"picturecountry",                LISTITEM_PICTURE_COUNTRY},
    {"picturecountrycode",            LISTITEM_PICTURE_COUNTRY_CODE},
    {"picturecredit",                 LISTITEM_PICTURE_CREDIT},
    {"pictureiptcdate",               LISTITEM_PICTURE_IPTCDATE},
    {"picturedigitalzoom",            LISTITEM_PICTURE_DIGITAL_ZOOM},
    {"pictureexposure",               LISTITEM_PICTURE_EXPOSURE},
    {"pictureexposurebias",           LISTITEM_PICTURE_EXPOSURE_BIAS},
    {"pictureflashused",              LISTITEM_PICTURE_FLASH_USED},
    {"pictureheadline",               LISTITEM_PICTURE_HEADLINE},
    {"picturecolour",                 LISTITEM_PICTURE_COLOUR},
    {"picturelightsource",            LISTITEM_PICTURE_LIGHT_SOURCE},
    {"picturemeteringmode",           LISTITEM_PICTURE_METERING_MODE},
    {"pictureobjectname",             LISTITEM_PICTURE_OBJECT_NAME},
    {"pictureorientation",            LISTITEM_PICTURE_ORIENTATION},
    {"pictureprocess",                LISTITEM_PICTURE_PROCESS},
    {"picturereferenceservice",       LISTITEM_PICTURE_REF_SERVICE},
    {"picturesource",                 LISTITEM_PICTURE_SOURCE},
    {"picturespecialinstructions",    LISTITEM_PICTURE_SPEC_INSTR},
    {"picturestate",                  LISTITEM_PICTURE_STATE},
    {"picturesupplementalcategories", LISTITEM_PICTURE_SUP_CATEGORIES},
    {"picturetransmissionreference",  LISTITEM_PICTURE_TX_REFERENCE},
    {"picturewhitebalance",           LISTITEM_PICTURE_WHITE_BALANCE},
    {"pictureimagetype",              LISTITEM_PICTURE_IMAGETYPE},
    {"picturesublocation",            LISTITEM_PICTURE_SUBLOCATION},
    {"pictureiptctime",               LISTITEM_PICTURE_TIMECREATED},
    {"picturegpslat",                 LISTITEM_PICTURE_GPS_LAT},
    {"picturegpslon",                 LISTITEM_PICTURE_GPS_LON},
    {"picturegpsalt",                 LISTITEM_PICTURE_GPS_ALT},
    {"studio",                        LISTITEM_STUDIO},
    {"country",                       LISTITEM_COUNTRY},
    {"mpaa",                          LISTITEM_MPAA},
    {"cast",                          LISTITEM_CAST},
    {"castandrole",                   LISTITEM_CAST_AND_ROLE},
    {"writer",                        LISTITEM_WRITER},
    {"tagline",                       LISTITEM_TAGLINE},
    {"status",                        LISTITEM_STATUS},
    {"top250",                        LISTITEM_TOP250},
    {"trailer",                       LISTITEM_TRAILER},
    {"sortletter",                    LISTITEM_SORT_LETTER},
    {"tag",                           LISTITEM_TAG},
    {"set",                           LISTITEM_SET},
    {"setid",                         LISTITEM_SETID},
    {"videocodec",                    LISTITEM_VIDEO_CODEC},
    {"videoresolution",               LISTITEM_VIDEO_RESOLUTION},
    {"videowidth",                    LISTITEM_VIDEO_WIDTH},
    {"videoheight",                   LISTITEM_VIDEO_HEIGHT},
    {"videoaspect",                   LISTITEM_VIDEO_ASPECT},
    {"audiocodec",                    LISTITEM_AUDIO_CODEC},
    {"audiochannels",                 LISTITEM_AUDIO_CHANNELS},
    {"audiolanguage",                 LISTITEM_AUDIO_LANGUAGE},
    {"subtitlelanguage",              LISTITEM_SUBTITLE_LANGUAGE},
    {"firstaudiolanguage",          LISTITEM_FIRST_AUDIO_LANGUAGE},
    {"firstsubtitlelanguage",       LISTITEM_FIRST_SUBTITLE_LANGUAGE},
    {"firstaudiocodec",             LISTITEM_FIRST_AUDIO_CODEC},
    {"firstaudiochannels",          LISTITEM_FIRST_AUDIO_CHANNELS},
    {"isresumable",                   LISTITEM_IS_RESUMABLE},
    {"percentplayed",                 LISTITEM_PERCENT_PLAYED},
    {"isfolder",                      LISTITEM_IS_FOLDER},
    {"isparentfolder",                LISTITEM_IS_PARENTFOLDER},
    {"iscollection",                  LISTITEM_IS_COLLECTION},
    {"originaltitle",                 LISTITEM_ORIGINALTITLE},
    {"lastplayed",                    LISTITEM_LASTPLAYED},
    {"playcount",                     LISTITEM_PLAYCOUNT},
    {"discnumber",                    LISTITEM_DISC_NUMBER},
    {"starttime",                     LISTITEM_STARTTIME},
    {"endtime",                       LISTITEM_ENDTIME},
    {"endtimeresume",                 LISTITEM_ENDTIME_RESUME},
    {"startdate",                     LISTITEM_STARTDATE},
    {"enddate",                       LISTITEM_ENDDATE},
    {"nexttitle",                     LISTITEM_NEXT_TITLE},
    {"nextgenre",                     LISTITEM_NEXT_GENRE},
    {"nextplot",                      LISTITEM_NEXT_PLOT},
    {"nextplotoutline",               LISTITEM_NEXT_PLOT_OUTLINE},
    {"nextstarttime",                 LISTITEM_NEXT_STARTTIME},
    {"nextendtime",                   LISTITEM_NEXT_ENDTIME},
    {"nextstartdate",                 LISTITEM_NEXT_STARTDATE},
    {"nextenddate",                   LISTITEM_NEXT_ENDDATE},
    {"nextduration",                  LISTITEM_NEXT_DURATION},
    {"channelname",                   LISTITEM_CHANNEL_NAME},
    {"channellogo",                   LISTITEM_CHANNEL_LOGO},
    {"channelnumberlabel",            LISTITEM_CHANNEL_NUMBER},
    {"channelgroup",                  LISTITEM_CHANNEL_GROUP},
    {"hasepg",                        LISTITEM_HAS_EPG},
    {"hastimer",                      LISTITEM_HASTIMER},
    {"hastimerschedule",              LISTITEM_HASTIMERSCHEDULE},
    {"hasreminder",                   LISTITEM_HASREMINDER},
    {"hasreminderrule",               LISTITEM_HASREMINDERRULE},
    {"hasrecording",                  LISTITEM_HASRECORDING},
    {"isrecording",                   LISTITEM_ISRECORDING},
    {"isplayable",                    LISTITEM_ISPLAYABLE},
    {"hasarchive",                    LISTITEM_HASARCHIVE},
    {"inprogress",                    LISTITEM_INPROGRESS},
    {"isencrypted",                   LISTITEM_ISENCRYPTED},
    {"progress",                      LISTITEM_PROGRESS},
    {"dateadded",                     LISTITEM_DATE_ADDED},
    {"dbtype",                        LISTITEM_DBTYPE},
    {"dbid",                          LISTITEM_DBID},
    {"appearances",                   LISTITEM_APPEARANCES},
    {"stereoscopicmode",              LISTITEM_STEREOSCOPIC_MODE},
    {"isstereoscopic",                LISTITEM_IS_STEREOSCOPIC},
    {"imdbnumber",                    LISTITEM_IMDBNUMBER},
    {"episodename",                   LISTITEM_EPISODENAME},
    {"timertype",                     LISTITEM_TIMERTYPE},
    {"epgeventtitle",                 LISTITEM_EPG_EVENT_TITLE},
    {"epgeventicon",                  LISTITEM_EPG_EVENT_ICON},
    {"timerisactive",                 LISTITEM_TIMERISACTIVE},
    {"timerhaserror",                 LISTITEM_TIMERHASERROR},
    {"timerhasconflict",              LISTITEM_TIMERHASCONFLICT},
    {"addonname",                     LISTITEM_ADDON_NAME},
    {"addonversion",                  LISTITEM_ADDON_VERSION},
    {"addoncreator",                  LISTITEM_ADDON_CREATOR},
    {"addonsummary",                  LISTITEM_ADDON_SUMMARY},
    {"addondescription",              LISTITEM_ADDON_DESCRIPTION},
    {"addondisclaimer",               LISTITEM_ADDON_DISCLAIMER},
    {"addonnews",                     LISTITEM_ADDON_NEWS},
    {"addonbroken",                   LISTITEM_ADDON_BROKEN},
    {"addonlifecycletype",            LISTITEM_ADDON_LIFECYCLE_TYPE},
    {"addonlifecycledesc",            LISTITEM_ADDON_LIFECYCLE_DESC},
    {"addontype",                     LISTITEM_ADDON_TYPE},
    {"addoninstalldate",              LISTITEM_ADDON_INSTALL_DATE},
    {"addonlastupdated",              LISTITEM_ADDON_LAST_UPDATED},
    {"addonlastused",                 LISTITEM_ADDON_LAST_USED},
    {"addonorigin",                   LISTITEM_ADDON_ORIGIN},
    {"addonsize",                     LISTITEM_ADDON_SIZE},
    {"expirationdate",                LISTITEM_EXPIRATION_DATE},
    {"expirationtime",                LISTITEM_EXPIRATION_TIME},
    {"art",                           LISTITEM_ART},
    {"property",                      LISTITEM_PROPERTY},
    {"parentalrating",                LISTITEM_PARENTAL_RATING},
    {"parentalratingcode",            LISTITEM_PARENTAL_RATING_CODE},
    {"parentalratingicon",            LISTITEM_PARENTAL_RATING_ICON},
    {"parentalratingsource",          LISTITEM_PARENTAL_RATING_SOURCE},
    {"currentitem",                   LISTITEM_CURRENTITEM},
    {"isnew",                         LISTITEM_IS_NEW},
    {"isboxset",                      LISTITEM_IS_BOXSET},
    {"totaldiscs",                    LISTITEM_TOTALDISCS},
    {"releasedate",                   LISTITEM_RELEASEDATE},
    {"originaldate",                  LISTITEM_ORIGINALDATE},
    {"bpm",                           LISTITEM_BPM},
    {"uniqueid",                      LISTITEM_UNIQUEID},
    {"bitrate",                       LISTITEM_BITRATE},
    {"samplerate",                    LISTITEM_SAMPLERATE},
    {"musicchannels",                 LISTITEM_MUSICCHANNELS},
    {"ispremiere",                    LISTITEM_IS_PREMIERE},
    {"isfinale",                      LISTITEM_IS_FINALE},
    {"islive",                        LISTITEM_IS_LIVE},
    {"tvshowdbid",                    LISTITEM_TVSHOWDBID},
    {"albumstatus",                   LISTITEM_ALBUMSTATUS},
    {"isautoupdateable",              LISTITEM_ISAUTOUPDATEABLE},
    {"hdrtype",                       LISTITEM_VIDEO_HDR_TYPE},
    {"songvideourl",                  LISTITEM_SONG_VIDEO_URL},
    {"hasvideoversions",              LISTITEM_HASVIDEOVERSIONS},
    {"isvideoextra",                  LISTITEM_ISVIDEOEXTRA},
    {"videoversionname",              LISTITEM_VIDEOVERSION_NAME},
    {"hasvideoextras",                LISTITEM_HASVIDEOEXTRAS},
    {"pvrclientname",                 LISTITEM_PVR_CLIENT_NAME},
    {"pvrinstancename",               LISTITEM_PVR_INSTANCE_NAME},
    {"pvrgrouporigin",                LISTITEM_PVR_GROUP_ORIGIN},
    {"episodepart",                   LISTITEM_EPISODEPART},
    {"mediaproviders",                LISTITEM_MEDIAPROVIDERS},
    {"titleextrainfo",                LISTITEM_TITLE_EXTRAINFO},
    {"hdrdetail",                     LISTITEM_VIDEO_HDR_DETAIL},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Visualisation Visualisation
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Visualisation.Enabled`</b>,
///                  \anchor Visualisation_Enabled
///                  _boolean_,
///     @return **True** if any visualisation has been set in settings (so not None).
///     <p>
///   }
///   \table_row3{   <b>`Visualisation.HasPresets`</b>,
///                  \anchor Visualisation_HasPresets
///                  _boolean_,
///     @return **True** if the visualisation has built in presets.
///     <p><hr>
///     @skinning_v16 **[New Boolean Condition]** \link Visualisation_HasPresets `Visualisation.HasPresets`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Visualisation.Locked`</b>,
///                  \anchor Visualisation_Locked
///                  _boolean_,
///     @return **True** if the current visualisation preset is locked (e.g. in Milkdrop).
///     <p>
///   }
///   \table_row3{   <b>`Visualisation.Preset`</b>,
///                  \anchor Visualisation_Preset
///                  _string_,
///     @return The current preset of the visualisation.
///     <p>
///   }
///   \table_row3{   <b>`Visualisation.Name`</b>,
///                  \anchor Visualisation_Name
///                  _string_,
///     @return the name of the visualisation.
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 5> visualisation = {{
    {"locked",      VISUALISATION_LOCKED},
    {"preset",      VISUALISATION_PRESET},
    {"haspresets",  VISUALISATION_HAS_PRESETS},
    {"name",        VISUALISATION_NAME},
    {"enabled",     VISUALISATION_ENABLED},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Fanart Fanart
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Fanart.Color1`</b>,
///                  \anchor Fanart_Color1
///                  _string_,
///     @return The first of three colors included in the currently selected
///     Fanart theme for the parent TV Show.
///     @note Colors are arranged Lightest to Darkest.
///     <p>
///   }
///   \table_row3{   <b>`Fanart.Color2`</b>,
///                  \anchor Fanart_Color2
///                  _string_,
///     @return The second of three colors included in the currently selected
///     Fanart theme for the parent TV Show.
///     @note Colors are arranged Lightest to Darkest.
///     <p>
///   }
///   \table_row3{   <b>`Fanart.Color3`</b>,
///                  \anchor Fanart_Color3
///                  _string_,
///     @return The third of three colors included in the currently selected
///     Fanart theme for the parent TV Show.
///     @note Colors are arranged Lightest to Darkest.
///     <p>
///   }
///   \table_row3{   <b>`Fanart.Image`</b>,
///                  \anchor Fanart_Image
///                  _string_,
///     @return The fanart image\, if any
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 4> fanart_labels = {{
    {"color1",  FANART_COLOR1},
    {"color2",  FANART_COLOR2},
    {"color3",  FANART_COLOR3},
    {"image",   FANART_IMAGE},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Skin Skin
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Skin.HasSetting(setting)`</b>,
///                  \anchor Skin_HasSetting
///                  _boolean_,
///     @param setting - the requested skin setting
///     @return **True** if the requested skin setting is true\, false otherwise.
///     @sa \link Skin_SetBool `Skin.SetBool(setting[\,value])`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Skin.String(setting)`</b>,
///                  \anchor Skin_StringValue
///                  _string_,
///     @param setting - the requested skin setting
///     @return The value of the requested string setting (as a string)
///     @sa \link Skin_SetString `Skin.SetString(setting[\,value])`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Skin.String(setting[\,value])`</b>,
///                  \anchor Skin_StringCompare
///                  _boolean_,
///     @param setting - the requested skin setting
///     @param value [opt] - the string value to compare the requested setting to
///     @return **True** if the setting value equals the provided value\, false otherwise.
///     @sa \link Skin_SetString `Skin.SetString(setting[\,value])`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Skin.HasTheme(theme)`</b>,
///                  \anchor Skin_HasTheme
///                  _boolean_,
///     @param theme - the requested skin theme
///     @return **True** if the requested theme is enabled\, false otherwise.
///     @sa \link Skin_CycleTheme `Skin.Theme()`\endlink and \link Skin_CurrentTheme `Skin.CurrentTheme`\endlink.
///     <p>
///   }
///   \table_row3{   <b>`Skin.CurrentTheme`</b>,
///                  \anchor Skin_CurrentTheme
///                  _string_,
///     @return The current selected skin theme.
///     <p>
///   }
///   \table_row3{   <b>`Skin.CurrentColourTheme`</b>,
///                  \anchor Skin_CurrentColourTheme
///                  _string_,
///     @return the current selected colour theme of the skin.
///     <p>
///   }
///   \table_row3{   <b>`Skin.AspectRatio`</b>,
///                  \anchor Skin_AspectRatio
///                  _string_,
///     @return The closest aspect ratio match using the resolution info from the skin's `addon.xml` file.
///     <p>
///   }
///   \table_row3{   <b>`Skin.Font`</b>,
///                  \anchor Skin_Font
///                  _string_,
///     @return the current fontset from `Font.xml`.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link Skin_Font `Skin.Font`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Skin.Numeric(settingid)`</b>,
///                  \anchor Skin_Numeric
///                  _integer_,
///     @return return the setting value as an integer/numeric value.
///     @sa \link Skin_SetNumeric `Skin.SetNumeric(settingid)`\endlink
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link Skin_Numeric `Skin.Numeric(settingid)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Skin.TimerElapsedSecs(timer)`</b>,
///                  \anchor Skin_TimerElapsedSecs
///                  _integer_ \, _string_,
///     @return The elapsed time in seconds for the provided `timer`.
///     @param timer - the timer name
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link Skin_TimerElapsedSecs `Skin.TimerElapsedSecs(timer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Skin.TimerIsRunning(timer)`</b>,
///                  \anchor Skin_TimerIsRunning
///                  _boolean_,
///     @return **True** if the given `timer` is active\, false otherwise.
///     @param timer - the timer name
///     <p><hr>
///     @skinning_v20 **[New Infolabel]** \link Skin_TimerIsRunning `Skin.TimerIsRunning(timer)`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 4> skin_labels = {{
    {"currenttheme",        SKIN_THEME},
    {"currentcolourtheme",  SKIN_COLOUR_THEME},
    {"aspectratio",         SKIN_ASPECT_RATIO},
    {"font",                SKIN_FONT},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Window Window
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Window.IsMedia`</b>,
///                  \anchor Window_IsMedia
///                  _boolean_,
///     @return **True** if this window is a media window (programs\, music\, video\,
///     scripts\, pictures)
///     <p>
///   }
///   \table_row3{   <b>`Window.Is(window)`</b>,
///                  \anchor Window_Is
///                  _boolean_,
///     @return **True** if the window with the given name is the window which is currently rendered.
///     @param window - the name of the window
///     @note Useful in xml files that are shared between multiple windows or dialogs.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \ref Window_Is "Window.Is(window)"
///     <p>
///   }
///   \table_row3{   <b>`Window.IsActive(window)`</b>,
///                  \anchor Window_IsActive
///                  _boolean_,
///     @return **True** if the window with id or title _window_ is active
///     @param window - the id or name of the window
///     @note Excludes fade out time on dialogs
///     <p>
///   }
///   \table_row3{   <b>`Window.IsVisible(window)`</b>,
///                  \anchor Window_IsVisible
///                  _boolean_,
///     @return **True** if the window is visible
///     @note Includes fade out time on dialogs
///     <p>
///   }
///   \table_row3{   <b>`Window.IsTopmost(window)`</b>,
///                  \anchor Window_IsTopmost
///                  _boolean_,
///     @return **True** if the window with id or title _window_ is on top of the
///     window stack.
///     @param window - the id or name of the window
///     @note Excludes fade out time on dialogs
///     @deprecated use  \ref Window_IsDialogTopmost "Window.IsDialogTopmost(dialog)" instead
///     <p>
///   }
///   \table_row3{   <b>`Window.IsDialogTopmost(dialog)`</b>,
///                  \anchor Window_IsDialogTopmost
///                  _boolean_,
///     @return **True** if the dialog with id or title _dialog_ is on top of the
///     dialog stack.
///     @param window - the id or name of the window
///     @note Excludes fade out time on dialogs
///     <p>
///   }
///   \table_row3{   <b>`Window.IsModalDialogTopmost(dialog)`</b>,
///                  \anchor Window_IsModalDialogTopmost
///                  _boolean_,
///     @return **True** if the dialog with id or title _dialog_ is on top of the
///     modal dialog stack
///     @note Excludes fade out time on dialogs
///     <p>
///   }
///   \table_row3{   <b>`Window.Previous(window)`</b>,
///                  \anchor Window_Previous
///                  _boolean_,
///     @return **True** if the window with id or title _window_ is being moved from.
///     @param window - the window id or title
///     @note Only valid while windows are changing.
///     <p>
///   }
///   \table_row3{   <b>`Window.Next(window)`</b>,
///                  \anchor Window_Next
///                  _boolean_,
///     @return **True** if the window with id or title _window_ is being moved to.
///     @param window - the window id or title
///     @note Only valid while windows are changing.
///     <p>
///   }
///   \table_row3{   <b>`Window.Property(Addon.ID)`</b>,
///                  \anchor Window_Property_AddonId
///                  _string_,
///     @return The id of the selected addon\, in `DialogAddonSettings.xml`.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link Window_Property_AddonId `Window.Property(Addon.ID)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Window.Property(IsRadio)`</b>,
///                  \anchor Window_Property_IsRadio
///                  _string_,
///     @return "true" if the window is a radio window\, empty string otherwise (for use in the PVR windows).
///     <p>
///   }
///   \table_row3{   <b>`Window([window]).Property(key)`</b>,
///                  \anchor Window_Window_Property_key
///                  _string_,
///     @return A window property.
///     @param window - [opt] window id or name.
///     @param key - any value.
///     <p>
///   }
///   \table_row3{   <b>`Window(AddonBrowser).Property(Updated)`</b>,
///                  \anchor Window_Addonbrowser_Property_Updated
///                  _string_,
///     @return The date and time the addon repo was last checked for updates.
///     @todo move to a future window document.
///     <p><hr>
///     @skinning_v15 **[New Infolabel]** \link Window_Addonbrowser_Property_Updated `Window(AddonBrowser).Property(Updated)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Window(Weather).Property(property)`</b>,
///                  \anchor Window_Weather_Property
///                  _string_,
///     @return The property for the weather window.
///     @param property - The requested property. The following are available:
///        - Current.ConditionIcon
///        - Day[0-6].OutlookIcon
///        - Current.FanartCode
///        - Day[0-6].FanartCode
///        - WeatherProviderLogo
///        - Daily.%i.OutlookIcon
///        - 36Hour.%i.OutlookIcon
///        - Weekend.%i.OutlookIcon
///        - Hourly.%i.OutlookIcon
///     @todo move to a future window document.
///     <p><hr>
///     @skinning_v16 **[Updated infolabel]** \link Window_Weather_Property `Window(Weather).Property(property)`\endlink
///     For skins that support extended weather info\, the following infolabels have been changed:
///       - Daily.%i.OutlookIcon
///       - 36Hour.%i.OutlookIcon
///       - Weekend.%i.OutlookIcon
///       - Hourly.%i.OutlookIcon
///
///     previously the openweathermap addon would provide the full\, hardcoded path to the icon
///     ie. `resource://resource.images.weathericons.default/28.png`
///     to make it easier for skins to work with custom icon sets\, it now will return the filename only
///     i.e. 28.png
///     @skinning_v13 **[Infolabel Updated]** \link Window_Weather_Property `Window(Weather).Property(property)`\endlink
///     added `WeatherProviderLogo` property - weather provider logo (for weather addons that support it).
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 9> window_bools = {{
    {"ismedia",               WINDOW_IS_MEDIA},
    {"is",                    WINDOW_IS},
    {"isactive",              WINDOW_IS_ACTIVE},
    {"isvisible",             WINDOW_IS_VISIBLE},
    {"istopmost",             WINDOW_IS_DIALOG_TOPMOST}, //! @deprecated, remove in v19
    {"isdialogtopmost",       WINDOW_IS_DIALOG_TOPMOST},
    {"ismodaldialogtopmost",  WINDOW_IS_MODAL_DIALOG_TOPMOST},
    {"previous",              WINDOW_PREVIOUS},
    {"next",                  WINDOW_NEXT},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Control Control
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`ControlGroup(id).HasFocus(controlid)`</b>,
///                  \anchor ControlGroup_HasFocus
///                  _boolean_,
///     @return **True** if the group with id "id" has focus. If "controlid" is
///     given\, **True** if that control is the one currently selected in the
///     group instead.
///     @param id - The id of the group
///     @param controlid - The id of a control in the group (optional)
///     <p>
///   }
///   \table_row3{   <b>`Control.HasFocus(id)`</b>,
///                  \anchor Control_HasFocus
///                  _boolean_,
///     @return **True** if the currently focused control has id "id".
///     @param id - The id of the control
///     <p>
///   }
///   \table_row3{   <b>`Control.IsVisible(id)`</b>,
///                  \anchor Control_IsVisible
///                  _boolean_,
///     @return **True** if the control with id "id" is visible.
///     @param id - The id of the control
///     <p>
///   }
///   \table_row3{   <b>`Control.IsEnabled(id)`</b>,
///                  \anchor Control_IsEnabled
///                  _boolean_,
///     @return **True** if the control with id "id" is enabled.
///     @param id - The id of the control
///     <p>
///   }
///   \table_row3{   <b>`Control.GetLabel(id)[.index()]`</b>,
///                  \anchor Control_GetLabel
///                  _string_,
///     @return The label value or texture name of the control with the given id.
///     @param id - The id of the control
///     @param index - [opt] Optionally you can specify index(1) to retrieve label2 from an Edit
///     control.
///     <p><hr>
///     @skinning_v15 **[Infolabel Updated]** \link Control_GetLabel `Control.GetLabel(id)`\endlink
///     added index parameter - allows skinner to retrieve label2 of a control. Only edit controls are supported.
///     ** Example** : `Control.GetLabel(999).index(1)` where:
///       - index(0) = label
///       - index(1) = label2
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 4> control_labels = {{
    {"hasfocus",  CONTROL_HAS_FOCUS},
    {"isvisible", CONTROL_IS_VISIBLE},
    {"isenabled", CONTROL_IS_ENABLED},
    {"getlabel",  CONTROL_GET_LABEL},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Playlist Playlist
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Playlist.Length(media)`</b>,
///                  \anchor Playlist_Length
///                  _integer_,
///     @return The total size of the current playlist.
///     @param media - [opt] mediatype with is either
///     video or music.
///     <p>
///   }
///   \table_row3{   <b>`Playlist.Position(media)`</b>,
///                  \anchor Playlist_Position
///                  _integer_,
///     @return The position of the current item in the current playlist.
///     @param media - [opt] mediatype with is either
///     video or music.
///     <p>
///   }
///   \table_row3{   <b>`Playlist.Random`</b>,
///                  \anchor Playlist_Random
///                  _integer_,
///     @return String ID for the random mode:
///       - **16041** (On)
///       - **591** (Off)
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link Playlist_Random `Playlist.Random`\endlink will
///     now return **On/Off**
///     <p>
///   }
///   \table_row3{   <b>`Playlist.Repeat`</b>,
///                  \anchor Playlist_Repeat
///                  _integer_,
///     @return The String Id for the repeat mode. It can be one of the following
///     values:
///       - **592** (Repeat One)
///       - **593** (Repeat All)
///       - **594** (Repeat Off)
///     <p>
///   }
///   \table_row3{   <b>`Playlist.IsRandom`</b>,
///                  \anchor Playlist_IsRandom
///                  _boolean_,
///     @return **True** if the player is in random mode.
///     <p>
///   }
///   \table_row3{   <b>`Playlist.IsRepeat`</b>,
///                  \anchor Playlist_IsRepeat
///                  _boolean_,
///     @return **True** if the player is in repeat all mode.
///     <p>
///   }
///   \table_row3{   <b>`Playlist.IsRepeatOne`</b>,
///                  \anchor Playlist_IsRepeatOne
///                  _boolean_,
///     @return **True** if the player is in repeat one mode.
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 7> playlist = {{
    {"length",      PLAYLIST_LENGTH},
    {"position",    PLAYLIST_POSITION},
    {"random",      PLAYLIST_RANDOM},
    {"repeat",      PLAYLIST_REPEAT},
    {"israndom",    PLAYLIST_ISRANDOM},
    {"isrepeat",    PLAYLIST_ISREPEAT},
    {"isrepeatone", PLAYLIST_ISREPEATONE},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Pvr Pvr
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`PVR.IsRecording`</b>,
///                  \anchor PVR_IsRecording
///                  _boolean_,
///     @return **True** when the system is recording a tv or radio programme.
///     <p>
///   }
///   \table_row3{   <b>`PVR.HasTimer`</b>,
///                  \anchor PVR_HasTimer
///                  _boolean_,
///     @return **True** when a recording timer is active.
///     <p>
///   }
///   \table_row3{   <b>`PVR.HasTVChannels`</b>,
///                  \anchor PVR_HasTVChannels
///                  _boolean_,
///     @return **True** if there are TV channels available.
///     <p>
///   }
///   \table_row3{   <b>`PVR.HasRadioChannels`</b>,
///                  \anchor PVR_HasRadioChannels
///                  _boolean_,
///     @return **True** if there are radio channels available.
///     <p>
///   }
///   \table_row3{   <b>`PVR.HasNonRecordingTimer`</b>,
///                  \anchor PVR_HasNonRecordingTimer
///                  _boolean_,
///     @return **True** if there are timers present who currently not do recording.
///     <p>
///   }
///   \table_row3{   <b>`PVR.BackendName`</b>,
///                  \anchor PVR_BackendName
///                  _string_,
///     @return The name of the backend being used.
///     <p>
///   }
///   \table_row3{   <b>`PVR.BackendVersion`</b>,
///                  \anchor PVR_BackendVersion
///                  _string_,
///     @return The version of the backend that's being used.
///     <p>
///   }
///   \table_row3{   <b>`PVR.BackendHost`</b>,
///                  \anchor PVR_BackendHost
///                  _string_,
///     @return The backend hostname.
///     <p>
///   }
///   \table_row3{   <b>`PVR.BackendDiskSpace`</b>,
///                  \anchor PVR_BackendDiskSpace
///                  _string_,
///     @return The available diskspace on the backend as string with size.
///     <p>
///   }
///   \table_row3{   <b>`PVR.BackendDiskSpaceProgr`</b>,
///                  \anchor PVR_BackendDiskSpaceProgr
///                  _integer_,
///     @return The available diskspace on the backend as percent value.
///     <p><hr>
///     @skinning_v14 **[New Infolabel]** \link PVR_BackendDiskSpaceProgr `PVR.BackendDiskSpaceProgr`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.BackendChannels`</b>,
///                  \anchor PVR_BackendChannels
///                  _string (integer)_,
///     @return The number of available channels the backend provides.
///     <p>
///   }
///   \table_row3{   <b>`PVR.BackendTimers`</b>,
///                  \anchor PVR_BackendTimers
///                  _string (integer)_,
///     @return The number of timers set for the backend.
///     <p>
///   }
///   \table_row3{   <b>`PVR.BackendRecordings`</b>,
///                  \anchor PVR_BackendRecordings
///                  _string (integer)_,
///     @return The number of recordings available on the backend.
///     <p>
///   }
///   \table_row3{   <b>`PVR.BackendDeletedRecordings`</b>,
///                  \anchor PVR_BackendDeletedRecordings
///                  _string (integer)_,
///     @return The number of deleted recordings present on the backend.
///     <p>
///   }
///   \table_row3{   <b>`PVR.BackendNumber`</b>,
///                  \anchor PVR_BackendNumber
///                  _string_,
///     @return The backend number.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TotalDiscSpace`</b>,
///                  \anchor PVR_TotalDiscSpace
///                  _string_,
///     @return The total diskspace available for recordings.
///     <p>
///   }
///   \table_row3{   <b>`PVR.NextTimer`</b>,
///                  \anchor PVR_NextTimer
///                  _boolean_,
///     @return The next timer date.
///     <p>
///   }
///   \table_row3{   <b>`PVR.IsPlayingTV`</b>,
///                  \anchor PVR_IsPlayingTV
///                  _boolean_,
///     @return **True** when live tv is being watched.
///     <p>
///   }
///   \table_row3{   <b>`PVR.IsPlayingRadio`</b>,
///                  \anchor PVR_IsPlayingRadio
///                  _boolean_,
///     @return **True** when live radio is being listened to.
///     <p>
///   }
///   \table_row3{   <b>`PVR.IsPlayingRecording`</b>,
///                  \anchor PVR_IsPlayingRecording
///                  _boolean_,
///     @return **True** when a recording is being watched.
///     <p>
///   }
///   \table_row3{   <b>`PVR.IsPlayingEpgTag`</b>,
///                  \anchor PVR_IsPlayingEpgTag
///                  _boolean_,
///     @return **True** when an epg tag is being watched.
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventProgress`</b>,
///                  \anchor PVR_EpgEventProgress
///                  _integer_,
///     @return The percentage complete of the currently playing epg event.
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link PVR_EpgEventProgress `PVR.EpgEventProgress`\endlink replaces
///     the old `PVR.Progress` infolabel.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamClient`</b>,
///                  \anchor PVR_ActStreamClient
///                  _string_,
///     @return The stream client name.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamDevice`</b>,
///                  \anchor PVR_ActStreamDevice
///                  _string_,
///     @return The stream device name.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamStatus`</b>,
///                  \anchor PVR_ActStreamStatus
///                  _string_,
///     @return The status of the stream.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamSignal`</b>,
///                  \anchor PVR_ActStreamSignal
///                  _string_,
///     @return The signal quality of the stream.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamSnr`</b>,
///                  \anchor PVR_ActStreamSnr
///                  _string_,
///     @return The signal to noise ratio of the stream.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamBer`</b>,
///                  \anchor PVR_ActStreamBer
///                  _string_,
///     @return The bit error rate of the stream.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamUnc`</b>,
///                  \anchor PVR_ActStreamUnc
///                  _string_,
///     @return The UNC value of the stream.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamProgrSignal`</b>,
///                  \anchor PVR_ActStreamProgrSignal
///                  _integer_,
///     @return The signal quality of the programme.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamProgrSnr`</b>,
///                  \anchor PVR_ActStreamProgrSnr
///                  _integer_,
///     @return The signal to noise ratio of the programme.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamIsEncrypted`</b>,
///                  \anchor PVR_ActStreamIsEncrypted
///                  _boolean_,
///     @return **True** when channel is encrypted on source.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamEncryptionName`</b>,
///                  \anchor PVR_ActStreamEncryptionName
///                  _string_,
///     @return The encryption used on the stream.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamServiceName`</b>,
///                  \anchor PVR_ActStreamServiceName
///                  _string_,
///     @return The service name of played channel if available.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamMux`</b>,
///                  \anchor PVR_ActStreamMux
///                  _string_,
///     @return The multiplex type of played channel if available.
///     <p>
///   }
///   \table_row3{   <b>`PVR.ActStreamProviderName`</b>,
///                  \anchor PVR_ActStreamProviderName
///                  _string_,
///     @return The provider name of the played channel if available.
///     <p>
///   }
///   \table_row3{   <b>`PVR.IsTimeShift`</b>,
///                  \anchor PVR_IsTimeShift
///                  _boolean_,
///     @return **True** when for channel is timeshift available.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeShiftProgress`</b>,
///                  \anchor PVR_TimeShiftProgress
///                  _integer_,
///     @return The position of currently timeshifted title on TV as integer.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeShiftSeekbar`</b>,
///                  \anchor PVR_TimeShiftSeekbar
///                  _integer_,
///     @return The percentage we are seeking to in a timeshifted title.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link PVR_TimeShiftSeekbar `PVR.TimeShiftSeekbar`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.NowRecordingTitle`</b>,
///                  \anchor PVR_NowRecordingTitle
///                  _string_,
///     @return The title of the programme being recorded.
///     <p>
///   }
///   \table_row3{   <b>`PVR.NowRecordingDateTime`</b>,
///                  \anchor PVR_NowRecordingDateTime
///                  _Date/Time string_,
///     @return The start date and time of the current recording.
///     <p>
///   }
///   \table_row3{   <b>`PVR.NowRecordingChannel`</b>,
///                  \anchor PVR_NowRecordingChannel
///                  _string_,
///     @return The channel name of the current recording.
///     <p>
///   }
///   \table_row3{   <b>`PVR.NowRecordingChannelIcon`</b>,
///                  \anchor PVR_NowRecordingChannelIcon
///                  _string_,
///     @return The icon of the current recording channel.
///     <p>
///   }
///   \table_row3{   <b>`PVR.NextRecordingTitle`</b>,
///                  \anchor PVR_NextRecordingTitle
///                  _string_,
///     @return The title of the next programme that will be recorded.
///     <p>
///   }
///   \table_row3{   <b>`PVR.NextRecordingDateTime`</b>,
///                  \anchor PVR_NextRecordingDateTime
///                  _Date/Time string_,
///     @return The start date and time of the next recording.
///     <p>
///   }
///   \table_row3{   <b>`PVR.NextRecordingChannel`</b>,
///                  \anchor PVR_NextRecordingChannel
///                  _string_,
///     @return The channel name of the next recording.
///     <p>
///   }
///   \table_row3{   <b>`PVR.NextRecordingChannelIcon`</b>,
///                  \anchor PVR_NextRecordingChannelIcon
///                  _string_,
///     @return The icon of the next recording channel.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TVNowRecordingTitle`</b>,
///                  \anchor PVR_TVNowRecordingTitle
///                  _string_,
///     @return The title of the tv programme being recorded.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_TVNowRecordingTitle `PVR.TVNowRecordingTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TVNowRecordingDateTime`</b>,
///                  \anchor PVR_TVNowRecordingDateTime
///                  _Date/Time string_,
///     @return The start date and time of the current tv recording.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_TVNowRecordingDateTime `PVR.TVNowRecordingDateTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TVNowRecordingChannel`</b>,
///                  \anchor PVR_TVNowRecordingChannel
///                  _string_,
///     @return The channel name of the current tv recording.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_TVNowRecordingChannel `PVR.TVNowRecordingChannel`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TVNowRecordingChannelIcon`</b>,
///                  \anchor PVR_TVNowRecordingChannelIcon
///                  _string_,
///     @return The icon of the current recording TV channel.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_TVNowRecordingChannelIcon `PVR.TVNowRecordingChannelIcon`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TVNextRecordingTitle`</b>,
///                  \anchor PVR_TVNextRecordingTitle
///                  _string_,
///     @return The title of the next tv programme that will be recorded.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_TVNextRecordingTitle `PVR.TVNextRecordingTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TVNextRecordingDateTime`</b>,
///                  \anchor PVR_TVNextRecordingDateTime
///                  _Date/Time string_,
///     @return The start date and time of the next tv recording.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_TVNextRecordingDateTime `PVR.TVNextRecordingDateTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TVNextRecordingChannel`</b>,
///                  \anchor PVR_TVNextRecordingChannel
///                  _string_,
///     @return The channel name of the next tv recording.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_TVNextRecordingChannel `PVR.TVNextRecordingChannel`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TVNextRecordingChannelIcon`</b>,
///                  \anchor PVR_TVNextRecordingChannelIcon
///                  _string_,
///     @return The icon of the next recording tv channel.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_TVNextRecordingChannelIcon `PVR.TVNextRecordingChannelIcon`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.RadioNowRecordingTitle`</b>,
///                  \anchor PVR_RadioNowRecordingTitle
///                  _string_,
///     @return The title of the radio programme being recorded.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_RadioNowRecordingTitle `PVR.RadioNowRecordingTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.RadioNowRecordingDateTime`</b>,
///                  \anchor PVR_RadioNowRecordingDateTime
///                  _Date/Time string_,
///     @return The start date and time of the current radio recording.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_RadioNowRecordingDateTime `PVR.RadioNowRecordingDateTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.RadioNowRecordingChannel`</b>,
///                  \anchor PVR_RadioNowRecordingChannel
///                  _string_,
///     @return The channel name of the current radio recording.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_RadioNowRecordingChannel `PVR.RadioNowRecordingChannel`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.RadioNowRecordingChannelIcon`</b>,
///                  \anchor PVR_RadioNowRecordingChannelIcon
///                  _string_,
///     @return The icon of the current recording radio channel.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_RadioNowRecordingChannelIcon `PVR.RadioNowRecordingChannelIcon`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.RadioNextRecordingTitle`</b>,
///                  \anchor PVR_RadioNextRecordingTitle
///                  _string_,
///     @return The title of the next radio programme that will be recorded.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_RadioNextRecordingTitle `PVR.RadioNextRecordingTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.RadioNextRecordingDateTime`</b>,
///                  \anchor PVR_RadioNextRecordingDateTime
///                  _Date/Time string_,
///     @return The start date and time of the next radio recording.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_RadioNextRecordingDateTime `PVR.RadioNextRecordingDateTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.RadioNextRecordingChannel`</b>,
///                  \anchor PVR_RadioNextRecordingChannel
///                  _string_,
///     @return The channel name of the next radio recording.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_RadioNextRecordingChannel `PVR.RadioNextRecordingChannel`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.RadioNextRecordingChannelIcon`</b>,
///                  \anchor PVR_RadioNextRecordingChannelIcon
///                  _string_,
///     @return The icon of the next recording radio channel.
///     <p><hr>
///     @skinning_v17 **[New Infolabel]** \link PVR_RadioNextRecordingChannelIcon `PVR.RadioNextRecordingChannelIcon`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.IsRecordingTV`</b>,
///                  \anchor PVR_IsRecordingTV
///                  _boolean_,
///     @return **True** when the system is recording a tv programme.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link PVR_IsRecordingTV `PVR.IsRecordingTV`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.HasTVTimer`</b>,
///                  \anchor PVR_HasTVTimer
///                  _boolean_,
///     @return **True** if at least one tv timer is active.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link PVR_HasTVTimer `PVR.HasTVTimer`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.HasNonRecordingTVTimer`</b>,
///                  \anchor PVR_HasNonRecordingTVTimer
///                  _boolean_,
///     @return **True** if there are tv timers present who currently not do recording.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link PVR_HasNonRecordingTVTimer `PVR.HasNonRecordingTVTimer`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.IsRecordingRadio`</b>,
///                  \anchor PVR_IsRecordingRadio
///                  _boolean_,
///     @return **True** when the system is recording a radio programme.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link PVR_IsRecordingRadio `PVR.IsRecordingRadio`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.HasRadioTimer`</b>,
///                  \anchor PVR_HasRadioTimer
///                  _boolean_,
///     @return **True** if at least one radio timer is active.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link PVR_HasRadioTimer `PVR.HasRadioTimer`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.HasNonRecordingRadioTimer`</b>,
///                  \anchor PVR_HasNonRecordingRadioTimer
///                  _boolean_,
///     @return **True** if there are radio timers present who currently not do recording.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link PVR_HasNonRecordingRadioTimer `PVR.HasRadioTimer`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.ChannelNumberInput`</b>,
///                  \anchor PVR_ChannelNumberInput
///                  _string_,
///     @return The currently entered channel number while in numeric channel input mode\, an empty string otherwise.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_ChannelNumberInput `PVR.ChannelNumberInput`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.CanRecordPlayingChannel`</b>,
///                  \anchor PVR_CanRecordPlayingChannel
///                  _boolean_,
///     @return **True** if PVR is currently playing a channel and if this channel can be recorded.
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link PVR_CanRecordPlayingChannel `PVR.CanRecordPlayingChannel`\endlink replaces
///     the old `Player.CanRecord` infolabel.
///     <p>
///   }
///   \table_row3{   <b>`PVR.IsRecordingPlayingChannel`</b>,
///                  \anchor PVR_IsRecordingPlayingChannel
///                  _boolean_,
///     @return **True** if PVR is currently playing a channel and if this channel is currently recorded.
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link PVR_IsRecordingPlayingChannel `PVR.IsRecordingPlayingChannel`\endlink replaces
///     the old `Player.Recording` infolabel.
///     <p>
///   }
///   \table_row3{   <b>`PVR.IsPlayingActiveRecording`</b>,
///                  \anchor PVR_IsPlayingActiveRecording
///                  _boolean_,
///     @return **True** if PVR is currently playing an in progress recording.
///     <p><hr>
///     @skinning_v19 **[New Infolabel]** \link PVR_IsPlayingActiveRecording `PVR.IsPlayingActiveRecording`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressPlayPos`</b>,
///                  \anchor PVR_TimeshiftProgressPlayPos
///                  _integer_,
///     @return The percentage of the current play position within the PVR timeshift progress.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressPlayPos `PVR.TimeshiftProgressPlayPos`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressEpgStart`</b>,
///                  \anchor PVR_TimeshiftProgressEpgStart
///                  _integer_,
///     @return The percentage of the start of the currently playing epg event within the PVR timeshift progress.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressEpgStart `PVR.TimeshiftProgressEpgStart`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressEpgEnd`</b>,
///                  \anchor PVR_TimeshiftProgressEpgEnd
///                  _integer_,
///     @return The percentage of the end of the currently playing epg event within the PVR timeshift progress.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressEpgEnd `PVR.TimeshiftProgressEpgEnd`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressBufferStart`</b>,
///                  \anchor PVR_TimeshiftProgressBufferStart
///                  _integer_,
///     @return The percentage of the start of the timeshift buffer within the PVR timeshift progress.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressBufferStart `PVR.TimeshiftProgressBufferStart`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressBufferEnd`</b>,
///                  \anchor PVR_TimeshiftProgressBufferEnd
///                  _integer_,
///     @return The percentage of the end of the timeshift buffer within the PVR timeshift progress.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressBufferEnd `PVR.TimeshiftProgressBufferEnd`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventIcon`</b>,
///                  \anchor PVR_EpgEventIcon
///                  _string_,
///     @return The icon of the currently playing epg event\, if any.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_EpgEventIcon `PVR.EpgEventIcon`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.ClientCount`</b>,
///                  \anchor PVR_ClientCount
///                  _integer_,
///     @return Number of PVR clients enabled.
///     <p><hr>
///     @skinning_v22 **[New Integer Value]** \link PVR_ClientCount `PVR.ClientCount`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.ClientName`</b>,
///                  \anchor PVR_ClientName
///                  _string_,
///     @return The name of the PVR client add-on\, as specified by the add-on developer.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link PVR_ClientName `PVR.ClientName`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.InstanceName`</b>,
///                  \anchor PVR_InstanceName
///                  _string_,
///     @return The name of the instance of the PVR client add-on\, as specified by the user in
///     the add-on settings. Empty if the PVR client add-on does not support multiple instances.
///     <p><hr>
///     @skinning_v22 **[New Infolabel]** \link PVR_InstanceName `PVR.InstanceName`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 82> pvr = {{
    {"isrecording",                   PVR_IS_RECORDING},
    {"hastimer",                      PVR_HAS_TIMER},
    {"hastvchannels",                 PVR_HAS_TV_CHANNELS},
    {"hasradiochannels",              PVR_HAS_RADIO_CHANNELS},
    {"hasnonrecordingtimer",          PVR_HAS_NONRECORDING_TIMER},
    {"backendname",                   PVR_BACKEND_NAME},
    {"backendversion",                PVR_BACKEND_VERSION},
    {"backendhost",                   PVR_BACKEND_HOST},
    {"backenddiskspace",              PVR_BACKEND_DISKSPACE},
    {"backenddiskspaceprogr",         PVR_BACKEND_DISKSPACE_PROGR},
    {"backendchannels",               PVR_BACKEND_CHANNELS},
    {"backendtimers",                 PVR_BACKEND_TIMERS},
    {"backendrecordings",             PVR_BACKEND_RECORDINGS},
    {"backenddeletedrecordings",      PVR_BACKEND_DELETED_RECORDINGS},
    {"backendnumber",                 PVR_BACKEND_NUMBER},
    {"totaldiscspace",                PVR_TOTAL_DISKSPACE},
    {"nexttimer",                     PVR_NEXT_TIMER},
    {"isplayingtv",                   PVR_IS_PLAYING_TV},
    {"isplayingradio",                PVR_IS_PLAYING_RADIO},
    {"isplayingrecording",            PVR_IS_PLAYING_RECORDING},
    {"isplayingepgtag",               PVR_IS_PLAYING_EPGTAG},
    {"epgeventprogress",              PVR_EPG_EVENT_PROGRESS},
    {"actstreamclient",               PVR_ACTUAL_STREAM_CLIENT},
    {"actstreamdevice",               PVR_ACTUAL_STREAM_DEVICE},
    {"actstreamstatus",               PVR_ACTUAL_STREAM_STATUS},
    {"actstreamsignal",               PVR_ACTUAL_STREAM_SIG},
    {"actstreamsnr",                  PVR_ACTUAL_STREAM_SNR},
    {"actstreamber",                  PVR_ACTUAL_STREAM_BER},
    {"actstreamunc",                  PVR_ACTUAL_STREAM_UNC},
    {"actstreamprogrsignal",          PVR_ACTUAL_STREAM_SIG_PROGR},
    {"actstreamprogrsnr",             PVR_ACTUAL_STREAM_SNR_PROGR},
    {"actstreamisencrypted",          PVR_ACTUAL_STREAM_ENCRYPTED},
    {"actstreamencryptionname",       PVR_ACTUAL_STREAM_CRYPTION},
    {"actstreamservicename",          PVR_ACTUAL_STREAM_SERVICE},
    {"actstreammux",                  PVR_ACTUAL_STREAM_MUX},
    {"actstreamprovidername",         PVR_ACTUAL_STREAM_PROVIDER},
    {"istimeshift",                   PVR_IS_TIMESHIFTING},
    {"timeshiftprogress",             PVR_TIMESHIFT_PROGRESS},
    {"timeshiftseekbar",              PVR_TIMESHIFT_SEEKBAR},
    {"nowrecordingtitle",             PVR_NOW_RECORDING_TITLE},
    {"nowrecordingdatetime",          PVR_NOW_RECORDING_DATETIME},
    {"nowrecordingchannel",           PVR_NOW_RECORDING_CHANNEL},
    {"nowrecordingchannelicon",       PVR_NOW_RECORDING_CHAN_ICO},
    {"nextrecordingtitle",            PVR_NEXT_RECORDING_TITLE},
    {"nextrecordingdatetime",         PVR_NEXT_RECORDING_DATETIME},
    {"nextrecordingchannel",          PVR_NEXT_RECORDING_CHANNEL},
    {"nextrecordingchannelicon",      PVR_NEXT_RECORDING_CHAN_ICO},
    {"tvnowrecordingtitle",           PVR_TV_NOW_RECORDING_TITLE},
    {"tvnowrecordingdatetime",        PVR_TV_NOW_RECORDING_DATETIME},
    {"tvnowrecordingchannel",         PVR_TV_NOW_RECORDING_CHANNEL},
    {"tvnowrecordingchannelicon",     PVR_TV_NOW_RECORDING_CHAN_ICO},
    {"tvnextrecordingtitle",          PVR_TV_NEXT_RECORDING_TITLE},
    {"tvnextrecordingdatetime",       PVR_TV_NEXT_RECORDING_DATETIME},
    {"tvnextrecordingchannel",        PVR_TV_NEXT_RECORDING_CHANNEL},
    {"tvnextrecordingchannelicon",    PVR_TV_NEXT_RECORDING_CHAN_ICO},
    {"radionowrecordingtitle",        PVR_RADIO_NOW_RECORDING_TITLE},
    {"radionowrecordingdatetime",     PVR_RADIO_NOW_RECORDING_DATETIME},
    {"radionowrecordingchannel",      PVR_RADIO_NOW_RECORDING_CHANNEL},
    {"radionowrecordingchannelicon",  PVR_RADIO_NOW_RECORDING_CHAN_ICO},
    {"radionextrecordingtitle",       PVR_RADIO_NEXT_RECORDING_TITLE},
    {"radionextrecordingdatetime",    PVR_RADIO_NEXT_RECORDING_DATETIME},
    {"radionextrecordingchannel",     PVR_RADIO_NEXT_RECORDING_CHANNEL},
    {"radionextrecordingchannelicon", PVR_RADIO_NEXT_RECORDING_CHAN_ICO},
    {"isrecordingtv",                 PVR_IS_RECORDING_TV},
    {"hastvtimer",                    PVR_HAS_TV_TIMER},
    {"hasnonrecordingtvtimer",        PVR_HAS_NONRECORDING_TV_TIMER},
    {"isrecordingradio",              PVR_IS_RECORDING_RADIO},
    {"hasradiotimer",                 PVR_HAS_RADIO_TIMER},
    {"hasnonrecordingradiotimer",     PVR_HAS_NONRECORDING_RADIO_TIMER},
    {"channelnumberinput",            PVR_CHANNEL_NUMBER_INPUT},
    {"canrecordplayingchannel",       PVR_CAN_RECORD_PLAYING_CHANNEL},
    {"isrecordingplayingchannel",     PVR_IS_RECORDING_PLAYING_CHANNEL},
    {"isplayingactiverecording",      PVR_IS_PLAYING_ACTIVE_RECORDING},
    {"timeshiftprogressplaypos",      PVR_TIMESHIFT_PROGRESS_PLAY_POS},
    {"timeshiftprogressepgstart",     PVR_TIMESHIFT_PROGRESS_EPG_START},
    {"timeshiftprogressepgend",       PVR_TIMESHIFT_PROGRESS_EPG_END},
    {"timeshiftprogressbufferstart",  PVR_TIMESHIFT_PROGRESS_BUFFER_START},
    {"timeshiftprogressbufferend",    PVR_TIMESHIFT_PROGRESS_BUFFER_END},
    {"epgeventicon",                  PVR_EPG_EVENT_ICON},
    {"clientcount",                   PVR_CLIENT_COUNT},
    {"clientname",                    PVR_CLIENT_NAME},
    {"instancename",                  PVR_INSTANCE_NAME},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
///   \table_row3{   <b>`PVR.EpgEventDuration`</b>,
///                  \anchor PVR_EpgEventDuration
///                  _string_,
///     @return The duration of the currently playing epg event in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link PVR_EpgEventDuration `PVR.EpgEventDuration`\endlink replaces
///     the old `PVR.Duration` infolabel.
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventDuration(format)`</b>,
///                  \anchor PVR_EpgEventDuration_format
///                  _string_,
///     @return The duration of the currently playing EPG event in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventElapsedTime`</b>,
///                  \anchor PVR_EpgEventElapsedTime
///                  _string_,
///     @return the time of the current position of the currently playing epg event in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p><hr>
///     @skinning_v18 **[Infolabel Updated]** \link PVR_EpgEventElapsedTime `PVR.EpgEventElapsedTime`\endlink replaces
///     the old `PVR.Time` infolabel.
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventElapsedTime(format)`</b>,
///                  \anchor PVR_EpgEventElapsedTime_format
///                  _string_,
///     @return The time of the current position of the currently playing epg event in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventRemainingTime`</b>,
///                  \anchor PVR_EpgEventRemainingTime
///                  _string_,
///     @return The remaining time for currently playing epg event in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_EpgEventRemainingTime `PVR.EpgEventRemainingTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventRemainingTime(format)`</b>,
///                  \anchor PVR_EpgEventRemainingTime_format
///                  _string_,
///     @return The remaining time for currently playing epg event in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventSeekTime`</b>,
///                  \anchor PVR_EpgEventSeekTime
///                  _string_,
///     @return The time the user is seeking within the currently playing epg event in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_EpgEventSeekTime `PVR.EpgEventSeekTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventSeekTime(format)`</b>,
///                  \anchor PVR_EpgEventSeekTime_format
///                  _string_,
///     @return The time the user is seeking within the currently playing epg event in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventFinishTime`</b>,
///                  \anchor PVR_EpgEventFinishTime
///                  _string_,
///     @return The time the currently playing epg event will end in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_EpgEventFinishTime `PVR.EpgEventFinishTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.EpgEventFinishTime(format)`</b>,
///                  \anchor PVR_EpgEventFinishTime_format
///                  _string_,
///     Returns the time the currently playing epg event will end in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeShiftStart`</b>,
///                  \anchor PVR_TimeShiftStart
///                  _string_,
///     @return The start time of the timeshift buffer in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeShiftStart(format)`</b>,
///                  \anchor PVR_TimeShiftStart_format
///                  _string_,
///     Returns the start time of the timeshift buffer in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeShiftEnd`</b>,
///                  \anchor PVR_TimeShiftEnd
///                  _string_,
///     @return The end time of the timeshift buffer in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeShiftEnd(format)`</b>,
///                  \anchor PVR_TimeShiftEnd_format
///                  _string_,
///     @return The end time of the timeshift buffer in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeShiftCur`</b>,
///                  \anchor PVR_TimeShiftCur
///                  _string_,
///     @return The current playback time within the timeshift buffer in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeShiftCur(format)`</b>,
///                  \anchor PVR_TimeShiftCur_format
///                  _string_,
///     Returns the current playback time within the timeshift buffer in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeShiftOffset`</b>,
///                  \anchor PVR_TimeShiftOffset
///                  _string_,
///     @return The delta of timeshifted time to actual time in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeShiftOffset(format)`</b>,
///                  \anchor PVR_TimeShiftOffset_format
///                  _string_,
///     Returns the delta of timeshifted time to actual time in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressDuration`</b>,
///                  \anchor PVR_TimeshiftProgressDuration
///                  _string_,
///     @return the duration of the PVR timeshift progress in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressDuration `PVR.TimeshiftProgressDuration`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressDuration(format)`</b>,
///                  \anchor PVR_TimeshiftProgressDuration_format
///                  _string_,
///     @return The duration of the PVR timeshift progress in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressStartTime`</b>,
///                  \anchor PVR_TimeshiftProgressStartTime
///                  _string_,
///     @return The start time of the PVR timeshift progress in the
///     format <b>hh:mm:ss</b>.
///     @note <b>hh:</b> will be omitted if hours value is zero.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressStartTime `PVR.TimeshiftProgressStartTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressStartTime(format)`</b>,
///                  \anchor PVR_TimeshiftProgressStartTime_format
///                  _string_,
///     @return The start time of the PVR timeshift progress in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressEndTime`</b>,
///                  \anchor PVR_TimeshiftProgressEndTime
///                  _string_,
///     @return The end time of the PVR timeshift progress in the
///     format <b>hh:mm:ss</b>.
///     @note hh: will be omitted if hours value is zero.
///     <p><hr>
///     @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressEndTime `PVR.TimeshiftProgressEndTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`PVR.TimeshiftProgressEndTime(format)`</b>,
///                  \anchor PVR_TimeshiftProgressEndTime_format
///                  _string_,
///     @return The end time of the PVR timeshift progress in different formats.
///     @param format [opt] The format of the return time value.
///     See \ref TIME_FORMAT for the list of possible values.
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 12> pvr_times = {{
    {"epgeventduration",            PVR_EPG_EVENT_DURATION},
    {"epgeventelapsedtime",         PVR_EPG_EVENT_ELAPSED_TIME},
    {"epgeventremainingtime",       PVR_EPG_EVENT_REMAINING_TIME},
    {"epgeventfinishtime",          PVR_EPG_EVENT_FINISH_TIME},
    {"epgeventseektime",            PVR_EPG_EVENT_SEEK_TIME},
    {"timeshiftstart",              PVR_TIMESHIFT_START_TIME},
    {"timeshiftend",                PVR_TIMESHIFT_END_TIME},
    {"timeshiftcur",                PVR_TIMESHIFT_PLAY_TIME},
    {"timeshiftoffset",             PVR_TIMESHIFT_OFFSET},
    {"timeshiftprogressduration",   PVR_TIMESHIFT_PROGRESS_DURATION},
    {"timeshiftprogressstarttime",  PVR_TIMESHIFT_PROGRESS_START_TIME},
    {"timeshiftprogressendtime",    PVR_TIMESHIFT_PROGRESS_END_TIME},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_RDS RDS
/// @note Only supported if both the PVR backend and the Kodi client support RDS.
///
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`RDS.HasRds`</b>,
///                  \anchor RDS_HasRds
///                  _boolean_,
///     @return **True** if RDS is present.
///     <p><hr>
///     @skinning_v16 **[New Boolean Condition]** \link RDS_HasRds `RDS.HasRds`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.HasRadioText`</b>,
///                  \anchor RDS_HasRadioText
///                  _boolean_,
///     @return **True** if RDS contains also RadioText.
///     <p><hr>
///     @skinning_v16 **[New Boolean Condition]** \link RDS_HasRadioText `RDS.HasRadioText`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.HasRadioTextPlus`</b>,
///                  \anchor RDS_HasRadioTextPlus
///                  _boolean_,
///     @return **True** if RDS with RadioText contains also the plus information.
///     <p><hr>
///     @skinning_v16 **[New Boolean Condition]** \link RDS_HasRadioTextPlus `RDS.HasRadioTextPlus`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.HasHotline`</b>,
///                  \anchor RDS_HasHotline
///                  _boolean_,
///     @return **True** if a hotline phone number is present.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Boolean Condition]** \link RDS_HasHotline `RDS.HasHotline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.HasStudio`</b>,
///                  \anchor RDS_HasStudio
///                  _boolean_,
///     @return **True** if a studio name is present.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Boolean Condition]** \link RDS_HasStudio `RDS.HasStudio`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.AudioLanguage`</b>,
///                  \anchor RDS_AudioLanguage
///                  _string_,
///     @return The RDS reported audio language of the channel.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_AudioLanguage `RDS.AudioLanguage`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.ChannelCountry`</b>,
///                  \anchor RDS_ChannelCountry
///                  _string_,
///     @return The country where the radio channel is broadcasted.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_ChannelCountry `RDS.ChannelCountry`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.GetLine(number)`</b>,
///                  \anchor RDS_GetLine
///                  _string_,
///     @return The last sent RDS text messages on given number.
///     @param number - given number for RDS\, 0 is the
///     last and 4 rows are supported (0-3)
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_GetLine `RDS.GetLine(number)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.Title`</b>,
///                  \anchor RDS_Title
///                  _string_,
///     @return The title of item; e.g. track title of an album.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_Title `RDS.Title`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.Artist`</b>,
///                  \anchor RDS_Artist
///                  _string_,
///     @return A person or band/collective generally considered responsible for the work.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_Artist `RDS.Artist`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.Band`</b>,
///                  \anchor RDS_Band
///                  _string_,
///     @return The band/orchestra/musician.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_Band `RDS.Band`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.Composer`</b>,
///                  \anchor RDS_Composer
///                  _string_,
///     @return The name of the original composer/author.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_Composer `RDS.Composer`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.Conductor`</b>,
///                  \anchor RDS_Conductor
///                  _string_,
///     @return The artist(s) who performed the work. In classical music this would be
///     the conductor.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_Conductor `RDS.Conductor`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.Album`</b>,
///                  \anchor RDS_Album
///                  _string_,
///     @return The album of the song.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_Album `RDS.Album`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.TrackNumber`</b>,
///                  \anchor RDS_TrackNumber
///                  _string_,
///     @return The track number of the item on the album on which it was originally
///     released.
///     @note Only be available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_TrackNumber `RDS.TrackNumber`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.RadioStyle`</b>,
///                  \anchor RDS_RadioStyle
///                  _string_,
///     @return The style of current played radio channel\, it is always
///     updated once the style changes\, e.g "popmusic" to "news" or "weather"...
///     | RDS                     | RBDS                    |
///     |:------------------------|:------------------------|
///     | none                    | none                    |
///     | news                    | news                    |
///     | currentaffairs          | information             |
///     | information             | sport                   |
///     | sport                   | talk                    |
///     | education               | rockmusic               |
///     | drama                   | classicrockmusic        |
///     | cultures                | adulthits               |
///     | science                 | softrock                |
///     | variedspeech            | top40                   |
///     | popmusic                | countrymusic            |
///     | rockmusic               | oldiesmusic             |
///     | easylistening           | softmusic               |
///     | lightclassics           | nostalgia               |
///     | seriousclassics         | jazzmusic               |
///     | othermusic              | classical               |
///     | weather                 | randb                   |
///     | finance                 | softrandb               |
///     | childrensprogs          | language                |
///     | socialaffairs           | religiousmusic          |
///     | religion                | religioustalk           |
///     | phonein                 | personality             |
///     | travelandtouring        | public                  |
///     | leisureandhobby         | college                 |
///     | jazzmusic               | spanishtalk             |
///     | countrymusic            | spanishmusic            |
///     | nationalmusic           | hiphop                  |
///     | oldiesmusic             |                         |
///     | folkmusic               |                         |
///     | documentary             | weather                 |
///     | alarmtest               | alarmtest               |
///     | alarm-alarm             | alarm-alarm             |
///     @note "alarm-alarm" is normally not used from radio stations\, is thought
///     to inform about horrible messages who are needed asap to all people.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_RadioStyle `RDS.RadioStyle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.Comment`</b>,
///                  \anchor RDS_Comment
///                  _string_,
///     @return The radio station comment string if available.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_Comment `RDS.Comment`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoNews`</b>,
///                  \anchor RDS_InfoNews
///                  _string_,
///     @return The message / headline (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoNews `RDS.InfoNews`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoNewsLocal`</b>,
///                  \anchor RDS_InfoNewsLocal
///                  _string_,
///     @return The local information news sended from radio channel (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoNewsLocal `RDS.InfoNewsLocal`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoStock`</b>,
///                  \anchor RDS_InfoStock
///                  _string_,
///     @return The stock information; either as one part or as several distinct parts:
///     "name 99latest value 99change 99high 99low 99volume" (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoStock `RDS.InfoStock`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoStockSize`</b>,
///                  \anchor RDS_InfoStockSize
///                  _string_,
///     @return The number of rows present in stock information.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoStockSize `RDS.InfoStockSize`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoSport`</b>,
///                  \anchor RDS_InfoSport
///                  _string_,
///     @return The result of a match; either as one part or as several distinct parts:
///     "match 99result"\, e.g. "Bayern München : Borussia 995:5"  (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoSport `RDS.InfoSport`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoSportSize`</b>,
///                  \anchor RDS_InfoSportSize
///                  _string_,
///     @return The number of rows present in sport information.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoSportSize `RDS.InfoSportSize`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoLottery`</b>,
///                  \anchor RDS_InfoLottery
///                  _string_,
///     @return The raffle / lottery: "key word 99values" (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoLottery `RDS.InfoLottery`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoLotterySize`</b>,
///                  \anchor RDS_InfoLotterySize
///                  _string_,
///     @return The number of rows present in lottery information.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoLotterySize `RDS.InfoLotterySize`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoWeather`</b>,
///                  \anchor RDS_InfoWeather
///                  _string_,
///     @return The weather information (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoWeather `RDS.InfoWeather`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoWeatherSize`</b>,
///                  \anchor RDS_InfoWeatherSize
///                  _string_,
///     @return The number of rows present in weather information.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoWeatherSize `RDS.InfoWeatherSize`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoCinema`</b>,
///                  \anchor RDS_InfoCinema
///                  _string_,
///     @return The information about movies in cinema (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoCinema `RDS.InfoCinema`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoCinemaSize`</b>,
///                  \anchor RDS_InfoCinemaSize
///                  _string_,
///     @return The number of rows present in cinema information.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoCinemaSize `RDS.InfoCinemaSize`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoHoroscope`</b>,
///                  \anchor RDS_InfoHoroscope
///                  _string_,
///     @return The horoscope; either as one part or as two distinct parts:
///     "key word 99text"\, e.g. "sign of the zodiac 99blablabla" (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoHoroscope `RDS.InfoHoroscope`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoHoroscopeSize`</b>,
///                  \anchor RDS_InfoHoroscopeSize
///                  _string_,
///     @return The Number of rows present in horoscope information.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoHoroscopeSize `RDS.InfoHoroscopeSize`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoOther`</b>,
///                  \anchor RDS_InfoOther
///                  _string_,
///     @return Other information\, not especially specified: "key word 99info" (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoOther `RDS.InfoOther`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.InfoOtherSize`</b>,
///                  \anchor RDS_InfoOtherSize
///                  _string_,
///     @return The number of rows present with other information.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_InfoOtherSize `RDS.InfoOtherSize`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.ProgStation`</b>,
///                  \anchor RDS_ProgStation
///                  _string_,
///     @return The name of the radio channel.
///     @note becomes also set from epg if it is not available from RDS
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_ProgStation `RDS.ProgStation`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.ProgNow`</b>,
///                  \anchor RDS_ProgNow
///                  _string_,
///     @return The now playing program name.
///     @note becomes also be set from epg if from RDS not available
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_ProgNow `RDS.ProgNow`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.ProgNext`</b>,
///                  \anchor RDS_ProgNext
///                  _string_,
///     @return The next played program name (if available).
///     @note becomes also be set from epg if from RDS not available
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_ProgNext `RDS.ProgNext`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.ProgHost`</b>,
///                  \anchor RDS_ProgHost
///                  _string_,
///     @return The name of the host of the radio show.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_ProgHost `RDS.ProgHost`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.ProgEditStaff`</b>,
///                  \anchor RDS_ProgEditStaff
///                  _string_,
///     @return The name of the editorial staff; e.g. name of editorial journalist.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_ProgEditStaff `RDS.ProgEditStaff`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.ProgHomepage`</b>,
///                  \anchor RDS_ProgHomepage
///                  _string_,
///     @return The Link to radio station homepage
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_ProgHomepage `RDS.ProgHomepage`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.ProgStyle`</b>,
///                  \anchor RDS_ProgStyle
///                  _string_,
///     @return A human readable string about radiostyle defined from RDS or RBDS.
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_ProgStyle `RDS.ProgStyle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.PhoneHotline`</b>,
///                  \anchor RDS_PhoneHotline
///                  _string_,
///     @return The telephone number of the radio station's hotline.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_PhoneHotline `RDS.PhoneHotline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.PhoneStudio`</b>,
///                  \anchor RDS_PhoneStudio
///                  _string_,
///     @return The telephone number of the radio station's studio.
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_PhoneStudio `RDS.PhoneStudio`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.SmsStudio`</b>,
///                  \anchor RDS_SmsStudio
///                  _string_,
///     @return The sms number of the radio stations studio (to send directly a sms to
///     the studio) (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_SmsStudio `RDS.SmsStudio`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.EmailHotline`</b>,
///                  \anchor RDS_EmailHotline
///                  _string_,
///     @return The email address of the radio stations hotline (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_EmailHotline `RDS.EmailHotline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`RDS.EmailStudio`</b>,
///                  \anchor RDS_EmailStudio
///                  _string_,
///     @return The email address of the radio station's studio (if available).
///     @note Only available on RadioText Plus
///     <p><hr>
///     @skinning_v16 **[New Infolabel]** \link RDS_EmailStudio `RDS.EmailStudio`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 45> rds = {{
    {"hasrds",            RDS_HAS_RDS},
    {"hasradiotext",      RDS_HAS_RADIOTEXT},
    {"hasradiotextplus",  RDS_HAS_RADIOTEXT_PLUS},
    {"audiolanguage",     RDS_AUDIO_LANG},
    {"channelcountry",    RDS_CHANNEL_COUNTRY},
    {"title",             RDS_TITLE},
    {"getline",           RDS_GET_RADIOTEXT_LINE},
    {"artist",            RDS_ARTIST},
    {"band",              RDS_BAND},
    {"composer",          RDS_COMPOSER},
    {"conductor",         RDS_CONDUCTOR},
    {"album",             RDS_ALBUM},
    {"tracknumber",       RDS_ALBUM_TRACKNUMBER},
    {"radiostyle",        RDS_GET_RADIO_STYLE},
    {"comment",           RDS_COMMENT},
    {"infonews",          RDS_INFO_NEWS},
    {"infonewslocal",     RDS_INFO_NEWS_LOCAL},
    {"infostock",         RDS_INFO_STOCK},
    {"infostocksize",     RDS_INFO_STOCK_SIZE},
    {"infosport",         RDS_INFO_SPORT},
    {"infosportsize",     RDS_INFO_SPORT_SIZE},
    {"infolottery",       RDS_INFO_LOTTERY},
    {"infolotterysize",   RDS_INFO_LOTTERY_SIZE},
    {"infoweather",       RDS_INFO_WEATHER},
    {"infoweathersize",   RDS_INFO_WEATHER_SIZE},
    {"infocinema",        RDS_INFO_CINEMA},
    {"infocinemasize",    RDS_INFO_CINEMA_SIZE},
    {"infohoroscope",     RDS_INFO_HOROSCOPE},
    {"infohoroscopesize", RDS_INFO_HOROSCOPE_SIZE},
    {"infoother",         RDS_INFO_OTHER},
    {"infoothersize",     RDS_INFO_OTHER_SIZE},
    {"progstation",       RDS_PROG_STATION},
    {"prognow",           RDS_PROG_NOW},
    {"prognext",          RDS_PROG_NEXT},
    {"proghost",          RDS_PROG_HOST},
    {"progeditstaff",     RDS_PROG_EDIT_STAFF},
    {"proghomepage",      RDS_PROG_HOMEPAGE},
    {"progstyle",         RDS_PROG_STYLE},
    {"phonehotline",      RDS_PHONE_HOTLINE},
    {"phonestudio",       RDS_PHONE_STUDIO},
    {"smsstudio",         RDS_SMS_STUDIO},
    {"emailhotline",      RDS_EMAIL_HOTLINE},
    {"emailstudio",       RDS_EMAIL_STUDIO},
    {"hashotline",        RDS_HAS_HOTLINE_DATA},
    {"hasstudio",         RDS_HAS_STUDIO_DATA},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_slideshow Slideshow
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Slideshow.IsActive`</b>,
///                  \anchor Slideshow_IsActive
///                  _boolean_,
///     @return **True** if the picture slideshow is running.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.IsPaused`</b>,
///                  \anchor Slideshow_IsPaused
///                  _boolean_,
///     @return **True** if the picture slideshow is paused.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.IsRandom`</b>,
///                  \anchor Slideshow_IsRandom
///                  _boolean_,
///     @return **True** if the picture slideshow is in random mode.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.IsVideo`</b>,
///                  \anchor Slideshow_IsVideo
///                  _boolean_,
///     @return **True** if the picture slideshow is playing a video.
///     <p><hr>
///     @skinning_v13 **[New Boolean Condition]** \link Slideshow_IsVideo `Slideshow.IsVideo`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Altitude`</b>,
///                  \anchor Slideshow_Altitude
///                  _string_,
///     @return The altitude in meters where the current picture was taken.
///     @note This is the value of the EXIF GPSInfo.GPSAltitude tag.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Aperture`</b>,
///                  \anchor Slideshow_Aperture
///                  _string_,
///     @return The F-stop used to take the current picture.
///     @note This is the value of the EXIF FNumber tag (hex code 0x829D).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Author`</b>,
///                  \anchor Slideshow_Author
///                  _string_,
///     @return The name of the person involved in writing about the current
///     picture.
///     @note This is the value of the IPTC Writer tag (hex code 0x7A).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Author `Slideshow.Author`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Byline`</b>,
///                  \anchor Slideshow_Byline
///                  _string_,
///     @return The name of the person who created the current picture.
///     @note This is the value of the IPTC Byline tag (hex code 0x50).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Byline `Slideshow.Byline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.BylineTitle`</b>,
///                  \anchor Slideshow_BylineTitle
///                  _string_,
///     @return The title of the person who created the current picture.
///     @note This is the value of the IPTC BylineTitle tag (hex code 0x55).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_BylineTitle `Slideshow.BylineTitle`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.CameraMake`</b>,
///                  \anchor Slideshow_CameraMake
///                  _string_,
///     @return The manufacturer of the camera used to take the current picture.
///     @note This is the value of the EXIF Make tag (hex code 0x010F).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.CameraModel`</b>,
///                  \anchor Slideshow_CameraModel
///                  _string_,
///     @return The manufacturer's model name or number of the camera used to take
///     the current picture.
///     @note This is the value of the EXIF Model tag (hex code 0x0110).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Caption`</b>,
///                  \anchor Slideshow_Caption
///                  _string_,
///     @return A description of the current picture.
///     @note This is the value of the IPTC Caption tag (hex code 0x78).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Category`</b>,
///                  \anchor Slideshow_Category
///                  _string_,
///     @return The subject of the current picture as a category code.
///     @note This is the value of the IPTC Category tag (hex code 0x0F).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Category `Slideshow.Category`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.CCDWidth`</b>,
///                  \anchor Slideshow_CCDWidth
///                  _string_,
///     @return The width of the CCD in the camera used to take the current
///     picture.
///     @note This is calculated from three EXIF tags (0xA002 * 0xA210 / 0xA20e).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_CCDWidth `Slideshow.CCDWidth`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.City`</b>,
///                  \anchor Slideshow_City
///                  _string_,
///     @return The city where the current picture was taken.
///     @note This is the value of the IPTC City tag (hex code 0x5A).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_City `Slideshow.City`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Colour`</b>,
///                  \anchor Slideshow_Colour
///                  _string_,
///     @return the colour of the picture. It can have one of the following values:
///       - <b>"Colour"</b>
///       - <b>"Black and White"</b>
///     <p>
///     @deprecated \link Slideshow_Colour `Slideshow.Colour`\endlink is deprecated and will be removed in future Kodi versions
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Colour `Slideshow.Colour`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.CopyrightNotice`</b>,
///                  \anchor Slideshow_CopyrightNotice
///                  _string_,
///     @return The copyright notice of the current picture.
///     @note This is the value of the IPTC Copyright tag (hex code 0x74).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_CopyrightNotice `Slideshow.CopyrightNotice`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Country`</b>,
///                  \anchor Slideshow_Country
///                  _string_,
///     @return The full name of the country where the current picture was taken.
///     @note This is the value of the IPTC CountryName tag (hex code 0x65).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Country `Slideshow.Country`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.CountryCode`</b>,
///                  \anchor Slideshow_CountryCode
///                  _string_,
///     @return The country code of the country where the current picture was
///     taken.
///     @note This is the value of the IPTC CountryCode tag (hex code 0x64).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_CountryCode `Slideshow.CountryCode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Credit`</b>,
///                  \anchor Slideshow_Credit
///                  _string_,
///     @return Who provided the current picture.
///     @note This is the value of the IPTC Credit tag (hex code 0x6E).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Credit `Slideshow.Credit`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.DigitalZoom`</b>,
///                  \anchor Slideshow_DigitalZoom
///                  _string_,
///     @return The digital zoom ratio when the current picture was taken.
///     @note This is the value of the EXIF .DigitalZoomRatio tag (hex code 0xA404).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_DigitalZoom `Slideshow.DigitalZoom`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.EXIFComment`</b>,
///                  \anchor Slideshow_EXIFComment
///                  _string_,
///     @return A description of the current picture.
///     @note This is the value of the EXIF User Comment tag (hex code 0x9286).
///     This is the same value as \ref Slideshow_SlideComment "Slideshow.SlideComment".
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.EXIFDate`</b>,
///                  \anchor Slideshow_EXIFDate
///                  _string_,
///     @return The localized date of the current picture. The short form of the
///     date is used.
///     @note The value of the EXIF DateTimeOriginal tag (hex code
///     0x9003) is preferred. If the DateTimeOriginal tag is not found\, the
///     value of DateTimeDigitized (hex code 0x9004) or of DateTime (hex code
///     0x0132) might be used.
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_EXIFDate `Slideshow.EXIFDate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.EXIFDescription`</b>,
///                  \anchor Slideshow_EXIFDescription
///                  _string_,
///     @return A short description of the current picture. The SlideComment\,
///     EXIFComment or Caption values might contain a longer description.
///     @note This is the value of the EXIF ImageDescription tag (hex code 0x010E).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.EXIFTime`</b>,
///                  \anchor Slideshow_EXIFTime
///                  _string_,
///     @return The date/timestamp of the current picture. The localized short
///     form of the date and time is used.
///     @note The value of the EXIF DateTimeOriginal tag (hex code 0x9003) is
///     preferred. If the DateTimeOriginal tag is not found\, the value of
///     DateTimeDigitized (hex code 0x9004) or of DateTime (hex code 0x0132)
///     might be used.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Exposure`</b>,
///                  \anchor Slideshow_Exposure
///                  _string_,
///     @return The class of the program used by the camera to set exposure when
///     the current picture was taken. Values include:
///      - <b>"Manual"</b>
///      - <b>"Program (Auto)"</b>
///      - <b>"Aperture priority (Semi-Auto)"</b>
///      - <b>"Shutter priority (semi-auto)"</b>
///      - etc...
///     @note This is the value of the EXIF ExposureProgram tag
///     (hex code 0x8822).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Exposure `Slideshow.Exposure`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.ExposureBias`</b>,
///                  \anchor Slideshow_ExposureBias
///                  _string_,
///     @return The exposure bias of the current picture. Typically this is a
///     number between -99.99 and 99.99.
///     @note This is the value of the EXIF ExposureBiasValue tag (hex code 0x9204).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_ExposureBias `Slideshow.ExposureBias`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.ExposureMode`</b>,
///                  \anchor Slideshow_ExposureMode
///                  _string_,
///     @return The exposure mode of the current picture. The possible values are:
///      - <b>"Automatic"</b>
///      - <b>"Manual"</b>
///      - <b>"Auto bracketing"</b>
///     @note This is the value of the EXIF ExposureMode tag (hex code 0xA402).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.ExposureTime`</b>,
///                  \anchor Slideshow_ExposureTime
///                  _string_,
///     @return The exposure time of the current picture\, in seconds.
///     @note This is the value of the EXIF ExposureTime tag (hex code 0x829A).
///     If the ExposureTime tag is not found\, the ShutterSpeedValue tag (hex code
///     0x9201) might be used.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Filedate`</b>,
///                  \anchor Slideshow_Filedate
///                  _string_,
///     @return The file date of the current picture.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Filename`</b>,
///                  \anchor Slideshow_Filename
///                  _string_,
///     @return The file name of the current picture.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Filesize`</b>,
///                  \anchor Slideshow_Filesize
///                  _string_,
///     @return The file size of the current picture.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.FlashUsed`</b>,
///                  \anchor Slideshow_FlashUsed
///                  _string_,
///     @return The status of flash when the current picture was taken. The value
///     will be either <b>"Yes"</b> or <b>"No"</b>\, and might include additional information.
///     @note This is the value of the EXIF Flash tag (hex code 0x9209).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_FlashUsed `Slideshow.FlashUsed`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.FocalLength`</b>,
///                  \anchor Slideshow_FocalLength
///                  _string_,
///     @return The focal length of the lens\, in mm.
///     @note This is the value of the EXIF FocalLength tag (hex code 0x920A).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.FocusDistance`</b>,
///                  \anchor Slideshow_FocusDistance
///                  _string_,
///     @return The distance to the subject\, in meters.
///     @note This is the value of the EXIF SubjectDistance tag (hex code 0x9206).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Headline`</b>,
///                  \anchor Slideshow_Headline
///                  _string_,
///     @return A synopsis of the contents of the current picture.
///     @note This is the value of the IPTC Headline tag (hex code 0x69).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Headline `Slideshow.Headline`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.ImageType`</b>,
///                  \anchor Slideshow_ImageType
///                  _string_,
///     @return The color components of the current picture.
///     @note This is the value of the IPTC ImageType tag (hex code 0x82).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_ImageType `Slideshow.ImageType`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.IPTCDate`</b>,
///                  \anchor Slideshow_IPTCDate
///                  _string_,
///     @return The date when the intellectual content of the current picture was
///     created\, rather than when the picture was created.
///     @note This is the value of the IPTC DateCreated tag (hex code 0x37).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.ISOEquivalence`</b>,
///                  \anchor Slideshow_ISOEquivalence
///                  _string_,
///     @return The ISO speed of the camera when the current picture was taken.
///     @note This is the value of the EXIF ISOSpeedRatings tag (hex code 0x8827).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Keywords`</b>,
///                  \anchor Slideshow_Keywords
///                  _string_,
///     @return The keywords assigned to the current picture.
///     @note This is the value of the IPTC Keywords tag (hex code 0x19).
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Latitude`</b>,
///                  \anchor Slideshow_Latitude
///                  _string_,
///     @return The latitude where the current picture was taken (degrees\,
///     minutes\, seconds North or South).
///     @note This is the value of the EXIF GPSInfo.GPSLatitude and
///     GPSInfo.GPSLatitudeRef tags.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.LightSource`</b>,
///                  \anchor Slideshow_LightSource
///                  _string_,
///     @return The kind of light source when the picture was taken. Possible
///     values include:
///      - <b>"Daylight"</b>
///      - <b>"Fluorescent"</b>
///      - <b>"Incandescent"</b>
///      - etc...
///     @note This is the value of the EXIF LightSource tag (hex code 0x9208).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_LightSource `Slideshow.LightSource`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.LongEXIFDate`</b>,
///                  \anchor Slideshow_LongEXIFDate
///                  _string_,
///     @return Only the localized date of the current picture. The long form of
///     the date is used.
///     @note The value of the EXIF DateTimeOriginal tag (hex code
///     0x9003) is preferred. If the DateTimeOriginal tag is not found\, the
///     value of DateTimeDigitized (hex code 0x9004) or of DateTime (hex code
///     0x0132) might be used.
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_LongEXIFDate `Slideshow.LongEXIFDate`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.LongEXIFTime`</b>,
///                  \anchor Slideshow_LongEXIFTime
///                  _string_,
///     @return The date/timestamp of the current picture. The localized long form
///     of the date and time is used.
///     @note The value of the EXIF DateTimeOriginal tag
///     (hex code 0x9003) is preferred. if the DateTimeOriginal tag is not found\,
///     the value of DateTimeDigitized (hex code 0x9004) or of DateTime (hex
///     code 0x0132) might be used.
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_LongEXIFTime `Slideshow.LongEXIFTime`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Longitude`</b>,
///                  \anchor Slideshow_Longitude
///                  _string_,
///     @return The longitude where the current picture was taken (degrees\,
///     minutes\, seconds East or West).
///     @note This is the value of the EXIF GPSInfo.GPSLongitude and
///     GPSInfo.GPSLongitudeRef tags.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.MeteringMode`</b>,
///                  \anchor Slideshow_MeteringMode
///                  _string_,
///     @return The metering mode used when the current picture was taken. The
///     possible values are:
///      - <b>"Center weight"</b>
///      - <b>"Spot"</b>
///      - <b>"Matrix"</b>
///     @note This is the value of the EXIF MeteringMode tag (hex code 0x9207).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_MeteringMode `Slideshow.MeteringMode`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.ObjectName`</b>,
///                  \anchor Slideshow_ObjectName
///                  _string_,
///     @return a shorthand reference for the current picture.
///     @note This is the value of the IPTC ObjectName tag (hex code 0x05).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_ObjectName `Slideshow.ObjectName`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Orientation`</b>,
///                  \anchor Slideshow_Orientation
///                  _string_,
///     @return The orientation of the current picture. Possible values are:
///      - <b>"Top Left"</b>
///      - <b>"Top Right"</b>
///      - <b>"Left Top"</b>
///      - <b>"Right Bottom"</b>
///      - etc...
///     @note This is the value of the EXIF Orientation tag (hex code 0x0112).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Orientation `Slideshow.Orientation`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Path`</b>,
///                  \anchor Slideshow_Path
///                  _string_,
///     @return The file path of the current picture.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Process`</b>,
///                  \anchor Slideshow_Process
///                  _string_,
///     @return The process used to compress the current picture.
///     <p>
///     @deprecated \link Slideshow_Process `Slideshow.Process`\endlink is deprecated and will be removed in future Kodi versions
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Process `Slideshow.Process`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.ReferenceService`</b>,
///                  \anchor Slideshow_ReferenceService
///                  _string_,
///     @return The Service Identifier of a prior envelope to which the current
///     picture refers.
///     @note This is the value of the IPTC ReferenceService tag (hex code 0x2D).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_ReferenceService `Slideshow.ReferenceService`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Resolution`</b>,
///                  \anchor Slideshow_Resolution
///                  _string_,
///     @return The dimensions of the current picture (Width x Height)
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.SlideComment`</b>,
///                  \anchor Slideshow_SlideComment
///                  _string_,
///     @return A description of the current picture.
///     @note This is the value of the EXIF User Comment tag (hex code 0x9286).
///     This is the same value as \ref Slideshow_EXIFComment "Slideshow.EXIFComment".
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.SlideIndex`</b>,
///                  \anchor Slideshow_SlideIndex
///                  _string_,
///     @return The slide index of the current picture.
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Source`</b>,
///                  \anchor Slideshow_Source
///                  _string_,
///     @return The original owner of the current picture.
///     @note This is the value of the IPTC Source tag (hex code 0x73).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Source `Slideshow.Source`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.SpecialInstructions`</b>,
///                  \anchor Slideshow_SpecialInstructions
///                  _string_,
///     @return Other editorial instructions concerning the use of the current
///     picture.
///     @note This is the value of the IPTC SpecialInstructions tag (hex code 0x28).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_SpecialInstructions `Slideshow.SpecialInstructions`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.State`</b>,
///                  \anchor Slideshow_State
///                  _string_,
///     @return The State/Province where the current picture was taken.
///     @note This is the value of the IPTC ProvinceState tag (hex code 0x5F).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_State `Slideshow.State`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Sublocation`</b>,
///                  \anchor Slideshow_Sublocation
///                  _string_,
///     @return The location within a city where the current picture was taken -
///     might indicate the nearest landmark.
///     @note This is the value of the IPTC SubLocation tag (hex code 0x5C).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Sublocation `Slideshow.Sublocation`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.SupplementalCategories`</b>,
///                  \anchor Slideshow_SupplementalCategories
///                  _string_,
///     @return The supplemental category codes to further refine the subject of the
///     current picture.
///     @note This is the value of the IPTC SuppCategory tag (hex
///     code 0x14).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_SupplementalCategories `Slideshow.SupplementalCategories`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.TimeCreated`</b>,
///                  \anchor Slideshow_TimeCreated
///                  _string_,
///     @return The time when the intellectual content of the current picture was
///     created\, rather than when the picture was created.
///     @note This is the value of the IPTC TimeCreated tag (hex code 0x3C).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_TimeCreated `Slideshow.TimeCreated`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.TransmissionReference`</b>,
///                  \anchor Slideshow_TransmissionReference
///                  _string_,
///     @return A code representing the location of original transmission of the
///     current picture.
///     @note This is the value of the IPTC TransmissionReference tag
///     (hex code 0x67).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_TransmissionReference `Slideshow.TransmissionReference`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.Urgency`</b>,
///                  \anchor Slideshow_Urgency
///                  _string_,
///     @return The urgency of the current picture. Values are 1-9. The 1 is most
///     urgent.
///     @note Some image management programs use urgency to indicate picture
///     rating\, where urgency 1 is 5 stars and urgency 5 is 1 star. Urgencies
///     6-9 are not used for rating. This is the value of the IPTC Urgency tag
///     (hex code 0x0A).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_Urgency `Slideshow.Urgency`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Slideshow.WhiteBalance`</b>,
///                  \anchor Slideshow_WhiteBalance
///                  _string_,
///     @return The white balance mode set when the current picture was taken.
///     The possible values are:
///       - <b>"Manual"</b>
///       - <b>"Auto"</b>
///     <p>
///     @note This is the value of the EXIF WhiteBalance tag (hex code 0xA403).
///     <p><hr>
///     @skinning_v13 **[New Infolabel]** \link Slideshow_WhiteBalance `Slideshow.WhiteBalance`\endlink
///     <p>
///   }
/// \table_end
///
/// -----------------------------------------------------------------------------
// clang-format off
constexpr std::array<InfoMap, 63> slideshow = {{
    {"ispaused",                SLIDESHOW_ISPAUSED},
    {"isactive",                SLIDESHOW_ISACTIVE},
    {"isvideo",                 SLIDESHOW_ISVIDEO},
    {"israndom",                SLIDESHOW_ISRANDOM},
    {"filename",                SLIDESHOW_FILE_NAME},
    {"path",                    SLIDESHOW_FILE_PATH},
    {"filesize",                SLIDESHOW_FILE_SIZE},
    {"filedate",                SLIDESHOW_FILE_DATE},
    {"slideindex",              SLIDESHOW_INDEX},
    {"resolution",              SLIDESHOW_RESOLUTION},
    {"slidecomment",            SLIDESHOW_COMMENT},
    {"colour",                  SLIDESHOW_COLOUR},
    {"process",                 SLIDESHOW_PROCESS},
    {"exiftime",                SLIDESHOW_EXIF_DATE_TIME},
    {"exifdate",                SLIDESHOW_EXIF_DATE},
    {"longexiftime",            SLIDESHOW_EXIF_LONG_DATE_TIME},
    {"longexifdate",            SLIDESHOW_EXIF_LONG_DATE},
    {"exifdescription",         SLIDESHOW_EXIF_DESCRIPTION},
    {"cameramake",              SLIDESHOW_EXIF_CAMERA_MAKE},
    {"cameramodel",             SLIDESHOW_EXIF_CAMERA_MODEL},
    {"exifcomment",             SLIDESHOW_EXIF_COMMENT},
    {"aperture",                SLIDESHOW_EXIF_APERTURE},
    {"focallength",             SLIDESHOW_EXIF_FOCAL_LENGTH},
    {"focusdistance",           SLIDESHOW_EXIF_FOCUS_DIST},
    {"exposure",                SLIDESHOW_EXIF_EXPOSURE},
    {"exposuretime",            SLIDESHOW_EXIF_EXPOSURE_TIME},
    {"exposurebias",            SLIDESHOW_EXIF_EXPOSURE_BIAS},
    {"exposuremode",            SLIDESHOW_EXIF_EXPOSURE_MODE},
    {"flashused",               SLIDESHOW_EXIF_FLASH_USED},
    {"whitebalance",            SLIDESHOW_EXIF_WHITE_BALANCE},
    {"lightsource",             SLIDESHOW_EXIF_LIGHT_SOURCE},
    {"meteringmode",            SLIDESHOW_EXIF_METERING_MODE},
    {"isoequivalence",          SLIDESHOW_EXIF_ISO_EQUIV},
    {"digitalzoom",             SLIDESHOW_EXIF_DIGITAL_ZOOM},
    {"ccdwidth",                SLIDESHOW_EXIF_CCD_WIDTH},
    {"orientation",             SLIDESHOW_EXIF_ORIENTATION},
    {"supplementalcategories",  SLIDESHOW_IPTC_SUP_CATEGORIES},
    {"keywords",                SLIDESHOW_IPTC_KEYWORDS},
    {"caption",                 SLIDESHOW_IPTC_CAPTION},
    {"author",                  SLIDESHOW_IPTC_AUTHOR},
    {"headline",                SLIDESHOW_IPTC_HEADLINE},
    {"specialinstructions",     SLIDESHOW_IPTC_SPEC_INSTR},
    {"category",                SLIDESHOW_IPTC_CATEGORY},
    {"byline",                  SLIDESHOW_IPTC_BYLINE},
    {"bylinetitle",             SLIDESHOW_IPTC_BYLINE_TITLE},
    {"credit",                  SLIDESHOW_IPTC_CREDIT},
    {"source",                  SLIDESHOW_IPTC_SOURCE},
    {"copyrightnotice",         SLIDESHOW_IPTC_COPYRIGHT_NOTICE},
    {"objectname",              SLIDESHOW_IPTC_OBJECT_NAME},
    {"city",                    SLIDESHOW_IPTC_CITY},
    {"state",                   SLIDESHOW_IPTC_STATE},
    {"country",                 SLIDESHOW_IPTC_COUNTRY},
    {"transmissionreference",   SLIDESHOW_IPTC_TX_REFERENCE},
    {"iptcdate",                SLIDESHOW_IPTC_DATE},
    {"urgency",                 SLIDESHOW_IPTC_URGENCY},
    {"countrycode",             SLIDESHOW_IPTC_COUNTRY_CODE},
    {"referenceservice",        SLIDESHOW_IPTC_REF_SERVICE},
    {"latitude",                SLIDESHOW_EXIF_GPS_LATITUDE},
    {"longitude",               SLIDESHOW_EXIF_GPS_LONGITUDE},
    {"altitude",                SLIDESHOW_EXIF_GPS_ALTITUDE},
    {"timecreated",             SLIDESHOW_IPTC_TIMECREATED},
    {"sublocation",             SLIDESHOW_IPTC_SUBLOCATION},
    {"imagetype",               SLIDESHOW_IPTC_IMAGETYPE},
}};
// clang-format on

/// \page modules__infolabels_boolean_conditions
/// \subsection modules__infolabels_boolean_conditions_Library Library
/// \table_start
///   \table_h3{ Labels, Type, Description }
///   \table_row3{   <b>`Library.IsScanning`</b>,
///                  \anchor Library_IsScanning
///                  _boolean_,
///     @return **True** if the library is being scanned.
///     <p>
///   }
///   \table_row3{   <b>`Library.IsScanningVideo`</b>,
///                  \anchor Library_IsScanningVideo
///                  _boolean_,
///     @return **True** if the video library is being scanned.
///     <p>
///   }
///   \table_row3{   <b>`Library.IsScanningMusic`</b>,
///                  \anchor Library_IsScanningMusic
///                  _boolean_,
///     @return **True** if the music library is being scanned.
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(music)`</b>,
///                  \anchor Library_HasContent_Music
///                  _boolean_,
///     @return **True** if the library has music content.
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(video)`</b>,
///                  \anchor Library_HasContent_Video
///                  _boolean_,
///     @return **True** if the library has video content.
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(movies)`</b>,
///                  \anchor Library_HasContent_Movies
///                  _boolean_,
///     @return **True** if the library has movies.
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(tvshows)`</b>,
///                  \anchor Library_HasContent_TVShows
///                  _boolean_,
///     @return **True** if the library has tvshows.
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(musicvideos)`</b>,
///                  \anchor Library_HasContent_MusicVideos
///                  _boolean_,
///     @return **True** if the library has music videos.
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(moviesets)`</b>,
///                  \anchor Library_HasContent_MovieSets
///                  _boolean_,
///     @return **True** if the library has movie sets.
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(singles)`</b>,
///                  \anchor Library_HasContent_Singles
///                  _boolean_,
///     @return **True** if the library has singles.
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(compilations)`</b>,
///                  \anchor Library_HasContent_Compilations
///                  _boolean_,
///     @return **True** if the library has compilations.
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(Role.Composer)`</b>,
///                  \anchor Library_HasContent_Role_Composer
///                  _boolean_,
///     @return **True** if there are songs in the library which have composers.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Composer `Library.HasContent(Role.Composer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(Role.Conductor)`</b>,
///                  \anchor Library_HasContent_Role_Conductor
///                  _boolean_,
///     @return **True** if there are songs in the library which have a conductor.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Conductor `Library.HasContent(Role.Conductor)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(Role.Orchestra)`</b>,
///                  \anchor Library_HasContent_Role_Orchestra
///                  _boolean_,
///     @return **True** if there are songs in the library which have an orchestra.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Orchestra `Library.HasContent(Role.Orchestra)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(Role.Lyricist)`</b>,
///                  \anchor Library_HasContent_Role_Lyricist
///                  _boolean_,
///     @return **True** if there are songs in the library which have a lyricist.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Lyricist `Library.HasContent(Role.Lyricist)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(Role.Remixer)`</b>,
///                  \anchor Library_HasContent_Role_Remixer
///                  _boolean_,
///     @return **True** if there are songs in the library which have a remixer.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Remixer `Library.HasContent(Role.Remixer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(Role.Arranger)`</b>,
///                  \anchor Library_HasContent_Role_Arranger
///                  _boolean_,
///     @return **True** if there are songs in the library which have an arranger.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Arranger `Library.HasContent(Role.Arranger)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(Role.Engineer)`</b>,
///                  \anchor Library_HasContent_Role_Engineer
///                  _boolean_,
///     @return **True** if there are songs in the library which have an engineer.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Engineer `Library.HasContent(Role.Engineer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(Role.Producer)`</b>,
///                  \anchor Library_HasContent_Role_Producer
///                  _boolean_,
///     @return **True** if there are songs in the library which have an producer.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Producer `Library.HasContent(Role.Producer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(Role.DJMixer)`</b>,
///                  \anchor Library_HasContent_Role_DJMixer
///                  _boolean_,
///     @return **True** if there are songs in the library which have a DJMixer.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_DJMixer `Library.HasContent(Role.DJMixer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(Role.Mixer)`</b>,
///                  \anchor Library_HasContent_Role_Mixer
///                  _boolean_,
///     @return **True** if there are songs in the library which have a mixer.
///     <p><hr>
///     @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Mixer `Library.HasContent(Role.Mixer)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasContent(boxsets)`</b>,
///                  \anchor Library_HasContent_Boxsets
///                  _boolean_,
///     @return **True** if there are albums in the library which are boxsets.
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link Library_HasContent_Boxsets `Library.HasContent(boxsets)`\endlink
///     <p>
///   }
///   \table_row3{   <b>`Library.HasNode(path)`</b>,
///                  \anchor Library_HasNode
///                  _boolean_,
///     @return **True** if there the node is present in the library.
///     <p><hr>
///     @skinning_v19 **[New Boolean Condition]** \link Library_HasNode `Library.HasNode(path)`\endlink
///     <p>
///   }
/// \table_end
/// @todo Make this annotate an array of infobools/labels to make it easier to track
///
/// -----------------------------------------------------------------------------

/// \page modules__infolabels_boolean_conditions
/// \section modules_rm_infolabels_booleans Additional revision history for Infolabels and Boolean Conditions
/// <hr>
/// \subsection modules_rm_infolabels_booleans_v22 Kodi v22
/// @skinning_v22 **[Removed Infolabels]** The following infolabels have been removed:
///   - `Player.Cutlist` - Please use \link Player_Editlist `Player.EditList`\endlink for the EDL list and \link Player_Cuts `Player.Cuts`\endlink for the cut markers
///   - `Slideshow.EXIFSoftware`- This infolabel was broken (did nothing) in previous versions. It might be re-added later.
///
/// <hr>
/// \subsection modules_rm_infolabels_booleans_v21 Kodi v21 (Omega)
/// @skinning_v21 **[Removed Infolabels]** The following infolabels have been removed:
///   - `Network.DHCPAddress` - this info did not return any meaningful value (always an empty string)
///
/// <hr>
/// \subsection modules_rm_infolabels_booleans_v20 Kodi v20 (Nexus)
/// @skinning_v20 **[Removed Boolean conditions]** The following boolean conditions have been removed:
///   - `Player.DisplayAfterSeek` - use \link Player_HasPerformedSeek `Player.HasPerformedSeek(interval)`\endlink instead
///
/// <hr>
/// \subsection modules_rm_infolabels_booleans_v19 Kodi v19 (Matrix)
/// @skinning_v19 **[Removed Infolabels]** The following infolabels have been removed:
///   - `System.Platform.Linux.RaspberryPi` - use \link System_PlatformLinux `System.Platform.Linux`\endlink instead
///
/// <hr>
/// \subsection modules_rm_infolabels_booleans_v18 Kodi v18 (Leia)
///
/// @skinning_v18 **[Removed Infolabels]** The following infolabels have been removed:
///   - `Listitem.Property(artistthumbs)`, `Listitem.Property(artistthumb)` - use
/// \link ListItem_Art_Type `ListItem.Art(type)`\endlink with <b>albumartist[n].*</b> or <b>artist[n].*</b> as <b>type</b>
///   - `ADSP.ActiveStreamType`
///   - `ADSP.DetectedStreamType`
///   - `ADSP.MasterName`
///   - `ADSP.MasterInfo`
///   - `ADSP.MasterOwnIcon`
///   - `ADSP.MasterOverrideIcon`
///   - `ListItem.ChannelNumber`, `ListItem.SubChannelNumber`, `MusicPlayer.ChannelNumber`,
/// `MusicPlayer.SubChannelNumber`, `VideoPlayer.ChannelNumber`,
/// `VideoPlayer.SubChannelNumber`. Please use the following alternatives
/// \link ListItem_ChannelNumberLabel `ListItem.ChannelNumberLabel` \endlink,
/// \link MusicPlayer_ChannelNumberLabel `MusicPlayer.ChannelNumberLabel` \endlink
/// \link VideoPlayer_ChannelNumberLabel `VideoPlayer.ChannelNumberLabel` \endlink from now on.
///
/// @skinning_v18 **[Removed Boolean Conditions]** The following infobools have been removed:
///   - `System.HasModalDialog`  - use \link System_HasActiveModalDialog `System.HasActiveModalDialog` \endlink and
///  \link System_HasVisibleModalDialog `System.HasVisibleModalDialog`\endlink instead
///   - `StringCompare()` - use \link String_IsEqual `String.IsEqual(info,string)`\endlink instead
///   - `SubString()` - use \link String_Contains `String.Contains(info,substring)`\endlink instead
///   - `IntegerGreaterThan()` - use \link Integer_IsGreater `Integer.IsGreater(info,number)`\endlink instead
///   - `IsEmpty()` - use \link String_IsEmpty `String.IsEmpty(info)`\endlink instead
///   - `System.HasADSP`
///   - `ADSP.IsActive`
///   - `ADSP.HasInputResample`
///   - `ADSP.HasPreProcess`
///   - `ADSP.HasMasterProcess`
///   - `ADSP.HasPostProcess`
///   - `ADSP.HasOutputResample`
///   - `ADSP.MasterActive`
/// <hr>
/// \subsection modules_rm_infolabels_booleans_v17 Kodi v17 (Krypton)
/// @skinning_v17 **[Removed Infolabels]** The following infolabels have been removed:
///   - `ListItem.StarRating` - use the other ratings instead.
///
/// @skinning_v17 **[Removed Boolean Conditions]** The following infobools have been removed:
///   - `on`  - use `true` instead
///   - `off`  - use `false` instead
///   - `Player.ShowCodec`
///   - `System.GetBool(pvrmanager.enabled)`
/// <hr>
/// \subsection modules_rm_infolabels_booleans_v16 Kodi v16 (Jarvis)
///  @skinning_v16 **[New Boolean Conditions]** The following infobools were added:
///    - `System.HasADSP`
///    - `ADSP.IsActive`
///    - `ADSP.HasInputResample`
///    - `ADSP.HasPreProcess`
///    - `ADSP.HasMasterProcess`
///    - `ADSP.HasPostProcess`
///    - `ADSP.HasOutputResample`
///    - `ADSP.MasterActive`
///    - `System.HasModalDialog`
///
///  @skinning_v16 **[New Infolabels]** The following infolabels were added:
///    - `ADSP.ActiveStreamType`
///    - `ADSP.DetectedStreamType`
///    - `ADSP.MasterName`
///    - `ADSP.MasterInfo`
///    - `ADSP.MasterOwnIcon`
///    - `ADSP.MasterOverrideIcon`
///
///   @skinning_v16 **[Removed Boolean Conditions]** The following infobols were removed:
///    - `System.Platform.ATV2`

/// <hr>
/// \subsection modules_rm_infolabels_booleans_v15 Kodi v15 (Isengard)
/// <hr>
/// \subsection modules_rm_infolabels_booleans_v14 Kodi v14 (Helix)
///  @skinning_v14 **[New Infolabels]** The following infolabels were added:
///    - `ListItem.SubChannelNumber`
///    - `MusicPlayer.SubChannelNumber`
///    - `VideoPlayer.SubChannelNumber`
///
/// <hr>
/// \subsection modules_rm_infolabels_booleans_v13 XBMC v13 (Gotham)
///   @skinning_v13 **[Removed Infolabels]** The following infolabels were removed:
///    - `Network.SubnetAddress`
///
/// <hr>
// Crazy part, to use tableofcontents must it be on end
/// \page modules__infolabels_boolean_conditions
/// \tableofcontents

} // unnamed namespace

CGUIInfoManager::CGUIInfoManager() : m_currentFile(std::make_unique<CFileItem>())
{
}

CGUIInfoManager::~CGUIInfoManager() = default;

void CGUIInfoManager::Initialize()
{
  CServiceBroker::GetAppMessenger()->RegisterReceiver(this);
}

/// \brief Translates a string as given by the skin into an int that we use for more
/// efficient retrieval of data. Can handle combined strings on the form
/// Player.Caching + VideoPlayer.IsFullscreen (Logical and)
/// Player.HasVideo | Player.HasAudio (Logical or)
int CGUIInfoManager::TranslateString(const std::string& condition)
{
  // translate $LOCALIZE as required
  std::string strCondition(CGUIInfoLabel::ReplaceLocalize(condition));
  return TranslateSingleString(strCondition);
}

CGUIInfoManager::Property::Property(const std::string& property, const std::string& parameters)
  : m_name(property)
{
  CUtil::SplitParams(parameters, params);
}

const std::string& CGUIInfoManager::Property::param(size_t n /* = 0 */) const
{
  if (n < params.size())
    return params[n];
  return StringUtils::Empty;
}

unsigned int CGUIInfoManager::Property::num_params() const
{
  return params.size();
}

void CGUIInfoManager::SplitInfoString(const std::string& infoString,
                                      std::vector<Property>& info) const
{
  // our string is of the form:
  // category[(params)][.info(params).info2(params)] ...
  // so we need to split on . while taking into account of () pairs
  unsigned int parentheses = 0;
  std::string property;
  std::string param;
  for (const char c : infoString)
  {
    if (c == '(')
    {
      if (!parentheses++)
        continue;
    }
    else if (c == ')')
    {
      if (!parentheses)
        CLog::Log(LOGERROR, "unmatched parentheses in {}", infoString);
      else if (!--parentheses)
        continue;
    }
    else if (c == '.' && !parentheses)
    {
      if (!property.empty()) // add our property and parameters
      {
        StringUtils::ToLower(property);
        info.emplace_back(property, param);
      }
      property.clear();
      param.clear();
      continue;
    }
    if (parentheses)
      param += c;
    else
      property += c;
  }

  if (parentheses)
    CLog::Log(LOGERROR, "unmatched parentheses in {}", infoString);

  if (!property.empty())
  {
    StringUtils::ToLower(property);
    info.emplace_back(property, param);
  }
}

/// \brief Translates a string as given by the skin into an int that we use for more
/// efficient retrieval of data.
int CGUIInfoManager::TranslateSingleString(const std::string& strCondition)
{
  bool listItemDependent;
  return TranslateSingleString(strCondition, listItemDependent);
}

namespace
{
std::string TranslateListSeparator(const std::string& param)
{
  if (StringUtils::EqualsNoCase(param, "comma"))
    return ", ";
  else if (StringUtils::EqualsNoCase(param, "pipe"))
    return " | ";
  else if (StringUtils::EqualsNoCase(param, "slash"))
    return " / ";
  else if (StringUtils::EqualsNoCase(param, "cr"))
    return "\n";
  else if (StringUtils::EqualsNoCase(param, "dash"))
    return " - ";
  else if (StringUtils::EqualsNoCase(param, "colon"))
    return " : ";
  else if (StringUtils::EqualsNoCase(param, "semicolon"))
    return "; ";
  else if (StringUtils::EqualsNoCase(param, "fullstop"))
    return ". ";
  else
  {
    CLog::Log(LOGERROR, "unhandled separator param {}", param);
    return {};
  }
}
} // unnamed namespace

int CGUIInfoManager::TranslateSingleString(const std::string& strCondition, bool& listItemDependent)
{
  /* We need to disable caching in INFO::InfoBool::Get if either of the following are true:
   *  1. if condition is between LISTITEM_START and LISTITEM_END
   *  2. if condition is string or integer the corresponding label is between LISTITEM_START and LISTITEM_END
   *  This is achieved by setting the bool pointed at by listItemDependent, either here or in a recursive call
   */
  // trim whitespaces
  std::string strTest = strCondition;
  StringUtils::Trim(strTest);

  std::vector<Property> info;
  SplitInfoString(strTest, info);

  if (info.empty())
    return 0;

  const Property& cat = info[0];
  if (info.size() == 1)
  { // single category
    if (cat.Name() == "false" || cat.Name() == "no")
      return SYSTEM_ALWAYS_FALSE;
    else if (cat.Name() == "true" || cat.Name() == "yes")
      return SYSTEM_ALWAYS_TRUE;
  }
  else if (info.size() == 2)
  {
    const Property& prop = info[1];
    if (cat.Name() == "string")
    {
      if (prop.Name() == "isempty")
      {
        return AddMultiInfo(
            CGUIInfo(STRING_IS_EMPTY, TranslateSingleString(prop.param(), listItemDependent)));
      }
      else if (prop.num_params() == 2)
      {
        for (const auto& string_bool : string_bools)
        {
          if (prop.Name() == string_bool.str)
          {
            int data1 = TranslateSingleString(prop.param(0), listItemDependent);
            // pipe our original string through the localize parsing then make it lowercase (picks up $LBRACKET etc.)
            std::string label = CGUIInfoLabel::GetLabel(prop.param(1), INFO::DEFAULT_CONTEXT);
            StringUtils::ToLower(label);
            // 'true', 'false', 'yes', 'no' are valid strings, do not resolve them to SYSTEM_ALWAYS_TRUE or SYSTEM_ALWAYS_FALSE
            if (label != "true" && label != "false" && label != "yes" && label != "no")
            {
              int data2 = TranslateSingleString(prop.param(1), listItemDependent);
              if (data2 > 0)
                return AddMultiInfo(CGUIInfo(string_bool.val, data1, -data2));
            }
            return AddMultiInfo(CGUIInfo(string_bool.val, data1, label));
          }
        }
      }
    }
    if (cat.Name() == "integer")
    {
      if (prop.Name() == "valueof")
      {
        int value = -1;
        std::from_chars(prop.param(0).data(), prop.param(0).data() + prop.param(0).size(), value);
        return AddMultiInfo(CGUIInfo(INTEGER_VALUEOF, value));
      }

      for (const auto& integer_bool : integer_bools)
      {
        if (prop.Name() == integer_bool.str)
        {
          std::array<int, 2> data = {-1, -1};
          for (size_t i = 0; i < data.size(); i++)
          {
            std::from_chars_result result = std::from_chars(
                prop.param(i).data(), prop.param(i).data() + prop.param(i).size(), data.at(i));
            if (result.ec == std::errc::invalid_argument)
            {
              // could not translate provided value to int, translate the info string
              data.at(i) = TranslateSingleString(prop.param(i), listItemDependent);
            }
            else
            {
              // conversion succeeded, integer value provided - translate it to an Integer.ValueOf() info.
              data.at(i) = AddMultiInfo(CGUIInfo(INTEGER_VALUEOF, data.at(i)));
            }
          }
          return AddMultiInfo(CGUIInfo(integer_bool.val, data.at(0), data.at(1)));
        }
      }
    }
    else if (cat.Name() == "player")
    {
      for (const auto& player_label : player_labels)
      {
        if (prop.Name() == player_label.str)
          return player_label.val;
      }
      for (const auto& player_time : player_times)
      {
        if (prop.Name() == player_time.str)
          return AddMultiInfo(CGUIInfo(player_time.val, TranslateTimeFormat(prop.param())));
      }
      if (prop.Name() == "process" && prop.num_params())
      {
        for (const auto& player_proces : player_process)
        {
          if (StringUtils::EqualsNoCase(prop.param(), player_proces.str))
            return player_proces.val;
        }
      }
      if (prop.num_params() == 1)
      {
        for (const auto& i : player_param)
        {
          if (prop.Name() == i.str)
            return AddMultiInfo(CGUIInfo(i.val, prop.param()));
        }
      }
    }
    else if (cat.Name() == "addon")
    {
      for (const auto& i : addons)
      {
        if (prop.Name() == i.str && prop.num_params() == 2)
          return AddMultiInfo(CGUIInfo(i.val, prop.param(0), prop.param(1)));
      }
    }
    else if (cat.Name() == "weather")
    {
      if (prop.num_params() == 0)
      {
        for (const auto& i : weather)
        {
          if (prop.Name() == i.str)
            return i.val;
        }
      }
      else if (prop.num_params() == 1)
      {
        if (prop.Name() == "data")
          return AddMultiInfo(CGUIInfo(WEATHER_DATA, prop.param(), 0));
      }
    }
    else if (cat.Name() == "network")
    {
      for (const auto& network_label : network_labels)
      {
        if (prop.Name() == network_label.str)
          return network_label.val;
      }
    }
    else if (cat.Name() == "musicpartymode")
    {
      for (const auto& i : musicpartymode)
      {
        if (prop.Name() == i.str)
          return i.val;
      }
    }
    else if (cat.Name() == "system")
    {
      for (const auto& system_label : system_labels)
      {
        if (prop.Name() == system_label.str)
          return system_label.val;
      }
      if (prop.num_params() == 1)
      {
        const std::string& param = prop.param();
        if (prop.Name() == "getbool")
        {
          std::string paramCopy = param;
          StringUtils::ToLower(paramCopy);
          return AddMultiInfo(CGUIInfo(SYSTEM_GET_BOOL, paramCopy));
        }
        for (const auto& i : system_param)
        {
          if (prop.Name() == i.str)
            return AddMultiInfo(CGUIInfo(i.val, param));
        }
        if (prop.Name() == "memory")
        {
          if (param == "free")
            return SYSTEM_FREE_MEMORY;
          else if (param == "free.percent")
            return SYSTEM_FREE_MEMORY_PERCENT;
          else if (param == "used")
            return SYSTEM_USED_MEMORY;
          else if (param == "used.percent")
            return SYSTEM_USED_MEMORY_PERCENT;
          else if (param == "total")
            return SYSTEM_TOTAL_MEMORY;
        }
        else if (prop.Name() == "addontitle")
        {
          // Example: System.AddonTitle(Skin.String(HomeVideosButton1)) => skin string HomeVideosButton1 holds an addon identifier string
          int infoLabel = TranslateSingleString(param, listItemDependent);
          if (infoLabel > 0)
            return AddMultiInfo(CGUIInfo(SYSTEM_ADDON_TITLE, infoLabel, 0));
          std::string label = CGUIInfoLabel::GetLabel(param, INFO::DEFAULT_CONTEXT);
          StringUtils::ToLower(label);
          return AddMultiInfo(CGUIInfo(SYSTEM_ADDON_TITLE, label, 1));
        }
        else if (prop.Name() == "addonicon")
        {
          int infoLabel = TranslateSingleString(param, listItemDependent);
          if (infoLabel > 0)
            return AddMultiInfo(CGUIInfo(SYSTEM_ADDON_ICON, infoLabel, 0));
          std::string label = CGUIInfoLabel::GetLabel(param, INFO::DEFAULT_CONTEXT);
          StringUtils::ToLower(label);
          return AddMultiInfo(CGUIInfo(SYSTEM_ADDON_ICON, label, 1));
        }
        else if (prop.Name() == "addonversion")
        {
          int infoLabel = TranslateSingleString(param, listItemDependent);
          if (infoLabel > 0)
            return AddMultiInfo(CGUIInfo(SYSTEM_ADDON_VERSION, infoLabel, 0));
          std::string label = CGUIInfoLabel::GetLabel(param, INFO::DEFAULT_CONTEXT);
          StringUtils::ToLower(label);
          return AddMultiInfo(CGUIInfo(SYSTEM_ADDON_VERSION, label, 1));
        }
        else if (prop.Name() == "idletime")
          return AddMultiInfo(CGUIInfo(SYSTEM_IDLE_TIME, atoi(param.c_str())));
        else if (prop.Name() == "locale")
        {
          if (param == "region")
          {
            return SYSTEM_LOCALE_REGION;
          }
          else if (param == "iso")
          {
            return SYSTEM_LOCALE;
          }
        }
      }
      if (prop.Name() == "alarmlessorequal" && prop.num_params() == 2)
        return AddMultiInfo(
            CGUIInfo(SYSTEM_ALARM_LESS_OR_EQUAL, prop.param(0), atoi(prop.param(1).c_str())));
      else if (prop.Name() == "date")
      {
        if (prop.num_params() == 2)
          return AddMultiInfo(CGUIInfo(SYSTEM_DATE,
                                       StringUtils::DateStringToYYYYMMDD(prop.param(0)) % 10000,
                                       StringUtils::DateStringToYYYYMMDD(prop.param(1)) % 10000));
        else if (prop.num_params() == 1)
        {
          int dateformat = StringUtils::DateStringToYYYYMMDD(prop.param(0));
          if (dateformat <= 0) // not concrete date
            return AddMultiInfo(CGUIInfo(SYSTEM_DATE, prop.param(0), -1));
          else
            return AddMultiInfo(CGUIInfo(SYSTEM_DATE, dateformat % 10000));
        }
        return SYSTEM_DATE;
      }
      else if (prop.Name() == "time")
      {
        if (prop.num_params() == 0)
          return AddMultiInfo(CGUIInfo(SYSTEM_TIME, TIME_FORMAT_GUESS));
        if (prop.num_params() == 1)
        {
          TIME_FORMAT timeFormat = TranslateTimeFormat(prop.param(0));
          if (timeFormat == TIME_FORMAT_GUESS)
            return AddMultiInfo(
                CGUIInfo(SYSTEM_TIME, StringUtils::TimeStringToSeconds(prop.param(0))));
          return AddMultiInfo(CGUIInfo(SYSTEM_TIME, timeFormat));
        }
        else
          return AddMultiInfo(CGUIInfo(SYSTEM_TIME, StringUtils::TimeStringToSeconds(prop.param(0)),
                                       StringUtils::TimeStringToSeconds(prop.param(1))));
      }
    }
    else if (cat.Name() == "library")
    {
      if (prop.Name() == "isscanning")
        return LIBRARY_IS_SCANNING;
      else if (prop.Name() == "isscanningvideo")
        return LIBRARY_IS_SCANNING_VIDEO; //! @todo change to IsScanning(Video)
      else if (prop.Name() == "isscanningmusic")
        return LIBRARY_IS_SCANNING_MUSIC;
      else if (prop.Name() == "hascontent" && prop.num_params())
      {
        std::string content{prop.param(0)};
        StringUtils::ToLower(content);
        if (content == "music")
          return LIBRARY_HAS_MUSIC;
        else if (content == "video")
          return LIBRARY_HAS_VIDEO;
        else if (content == "movies")
          return LIBRARY_HAS_MOVIES;
        else if (content == "tvshows")
          return LIBRARY_HAS_TVSHOWS;
        else if (content == "musicvideos")
          return LIBRARY_HAS_MUSICVIDEOS;
        else if (content == "moviesets")
          return LIBRARY_HAS_MOVIE_SETS;
        else if (content == "singles")
          return LIBRARY_HAS_SINGLES;
        else if (content == "compilations")
          return LIBRARY_HAS_COMPILATIONS;
        else if (content == "boxsets")
          return LIBRARY_HAS_BOXSETS;
        else if (content == "role" && prop.num_params() > 1)
          return AddMultiInfo(CGUIInfo(LIBRARY_HAS_ROLE, prop.param(1), 0));
      }
      else if (prop.Name() == "hasnode" && prop.num_params())
      {
        std::string node = prop.param(0);
        StringUtils::ToLower(node);
        return AddMultiInfo(CGUIInfo(LIBRARY_HAS_NODE, prop.param(), 0));
      }
    }
    else if (cat.Name() == "musicplayer")
    {
      for (const auto& player_time : player_times) //! @todo remove these, they're repeats
      {
        if (prop.Name() == player_time.str)
          return AddMultiInfo(CGUIInfo(player_time.val, TranslateTimeFormat(prop.param())));
      }
      if (prop.Name() == "content" && prop.num_params())
      {
        return AddMultiInfo(CGUIInfo(MUSICPLAYER_CONTENT, prop.param(), 0));
      }
      else if (prop.Name() == "genre" && prop.num_params() > 0)
      {
        return AddMultiInfo(CGUIInfo(MUSICPLAYER_GENRE, TranslateListSeparator(prop.param()), 0));
      }
      else if (prop.Name() == "property")
      {
        if (StringUtils::EqualsNoCase(prop.param(), "fanart_image"))
          return AddMultiInfo(CGUIInfo(PLAYER_ITEM_ART, "fanart"));

        return AddMultiInfo(CGUIInfo(MUSICPLAYER_PROPERTY, prop.param()));
      }
      else if (prop.Name() == "channels" && prop.num_params() == 1)
      {
        return AddMultiInfo(CGUIInfo(MUSICPLAYER_CHANNELS, prop.param()));
      }

      return TranslateMusicPlayerString(prop.Name());
    }
    else if (cat.Name() == "videoplayer")
    {
      if (prop.Name() !=
          "starttime") // player.starttime is semantically different from videoplayer.starttime which has its own implementation!
      {
        for (const auto& player_time : player_times) //! @todo remove these, they're repeats
        {
          if (prop.Name() == player_time.str)
            return AddMultiInfo(CGUIInfo(player_time.val, TranslateTimeFormat(prop.param())));
        }
      }
      if (prop.Name() == "content" && prop.num_params())
      {
        return AddMultiInfo(CGUIInfo(VIDEOPLAYER_CONTENT, prop.param(), 0));
      }
      if (prop.Name() == "uniqueid" && prop.num_params())
      {
        return AddMultiInfo(CGUIInfo(VIDEOPLAYER_UNIQUEID, prop.param(), 0));
      }
      if (prop.Name() == "art" && prop.num_params() > 0)
      {
        return AddMultiInfo(CGUIInfo(VIDEOPLAYER_ART, prop.param(), 0));
      }
      if (prop.Name() == "cast" && prop.num_params() > 0)
      {
        return AddMultiInfo(CGUIInfo(VIDEOPLAYER_CAST, TranslateListSeparator(prop.param()), 0));
      }
      if (prop.Name() == "castandrole" && prop.num_params() > 0)
      {
        return AddMultiInfo(
            CGUIInfo(VIDEOPLAYER_CAST_AND_ROLE, TranslateListSeparator(prop.param()), 0));
      }
      if (prop.Name() == "writer" && prop.num_params() > 0)
      {
        return AddMultiInfo(CGUIInfo(VIDEOPLAYER_WRITER, TranslateListSeparator(prop.param()), 0));
      }
      if (prop.Name() == "director" && prop.num_params() > 0)
      {
        return AddMultiInfo(
            CGUIInfo(VIDEOPLAYER_DIRECTOR, TranslateListSeparator(prop.param()), 0));
      }
      if (prop.Name() == "genre" && prop.num_params() > 0)
      {
        return AddMultiInfo(CGUIInfo(VIDEOPLAYER_GENRE, TranslateListSeparator(prop.param()), 0));
      }
      if (prop.Name() == "nextgenre" && prop.num_params() > 0)
      {
        return AddMultiInfo(
            CGUIInfo(VIDEOPLAYER_NEXT_GENRE, TranslateListSeparator(prop.param()), 0));
      }

      if (prop.Name() == "audiochannels" && prop.num_params() == 1)
        return AddMultiInfo(CGUIInfo(VIDEOPLAYER_AUDIO_CHANNELS, prop.param(), 0));

      return TranslateVideoPlayerString(prop.Name());
    }
    else if (cat.Name() == "retroplayer")
    {
      for (const auto& i : retroplayer)
      {
        if (prop.Name() == i.str)
          return i.val;
      }
    }
    else if (cat.Name() == "slideshow")
    {
      for (const auto& i : slideshow)
      {
        if (prop.Name() == i.str)
          return i.val;
      }
    }
    else if (cat.Name() == "container")
    {
      for (const auto& i : mediacontainer) // these ones don't have or need an id
      {
        if (prop.Name() == i.str)
          return i.val;
      }
      int id = atoi(cat.param().c_str());
      for (const auto& container_bool :
           container_bools) // these ones can have an id (but don't need to?)
      {
        if (prop.Name() == container_bool.str)
          return id ? AddMultiInfo(CGUIInfo(container_bool.val, id)) : container_bool.val;
      }
      for (const auto& container_int :
           container_ints) // these ones can have an int param on the property
      {
        if (prop.Name() == container_int.str)
          return AddMultiInfo(CGUIInfo(container_int.val, id, atoi(prop.param().c_str())));
      }
      for (const auto& i : container_str) // these ones have a string param on the property
      {
        if (prop.Name() == i.str)
          return AddMultiInfo(CGUIInfo(i.val, id, prop.param()));
      }
      if (prop.Name() == "sortdirection")
      {
        SortOrder order = SortOrder::NONE;
        if (StringUtils::EqualsNoCase(prop.param(), "ascending"))
          order = SortOrder::ASCENDING;
        else if (StringUtils::EqualsNoCase(prop.param(), "descending"))
          order = SortOrder::DESCENDING;
        return AddMultiInfo(CGUIInfo(CONTAINER_SORT_DIRECTION, static_cast<int>(order)));
      }
    }
    else if (cat.Name() == "listitem" || cat.Name() == "listitemposition" ||
             cat.Name() == "listitemnowrap" || cat.Name() == "listitemabsolute")
    {
      int ret = TranslateListItem(cat, prop, 0, false);
      if (ret)
        listItemDependent = true;
      return ret;
    }
    else if (cat.Name() == "visualisation")
    {
      for (const auto& i : visualisation)
      {
        if (prop.Name() == i.str)
          return i.val;
      }
    }
    else if (cat.Name() == "fanart")
    {
      for (const auto& fanart_label : fanart_labels)
      {
        if (prop.Name() == fanart_label.str)
          return fanart_label.val;
      }
    }
    else if (cat.Name() == "skin")
    {
      for (const auto& skin_label : skin_labels)
      {
        if (prop.Name() == skin_label.str)
          return skin_label.val;
      }
      if (prop.num_params())
      {
        if (prop.Name() == "string")
        {
          if (prop.num_params() == 2)
            return AddMultiInfo(CGUIInfo(
                SKIN_STRING_IS_EQUAL, CSkinSettings::GetInstance().TranslateString(prop.param(0)),
                prop.param(1)));
          else
            return AddMultiInfo(
                CGUIInfo(SKIN_STRING, CSkinSettings::GetInstance().TranslateString(prop.param(0))));
        }
        else if (prop.Name() == "numeric")
        {
          return AddMultiInfo(
              CGUIInfo(SKIN_INTEGER, CSkinSettings::GetInstance().TranslateString(prop.param(0))));
        }
        else if (prop.Name() == "hassetting")
          return AddMultiInfo(
              CGUIInfo(SKIN_BOOL, CSkinSettings::GetInstance().TranslateBool(prop.param(0))));
        else if (prop.Name() == "hastheme")
          return AddMultiInfo(CGUIInfo(SKIN_HAS_THEME, prop.param(0)));
        else if (prop.Name() == "timerisrunning")
          return AddMultiInfo(CGUIInfo(SKIN_TIMER_IS_RUNNING, prop.param(0)));
        else if (prop.Name() == "timerelapsedsecs")
          return AddMultiInfo(CGUIInfo(SKIN_TIMER_ELAPSEDSECS, prop.param(0)));
      }
    }
    else if (cat.Name() == "window")
    {
      if (prop.Name() == "property" && prop.num_params() == 1)
      { //! @todo this doesn't support foo.xml
        int winID = cat.param().empty() ? 0 : CWindowTranslator::TranslateWindow(cat.param());
        if (winID != WINDOW_INVALID)
          return AddMultiInfo(CGUIInfo(WINDOW_PROPERTY, winID, prop.param()));
      }
      for (const auto& window_bool : window_bools)
      {
        if (prop.Name() == window_bool.str)
        { //! @todo The parameter for these should really be on the first not the second property
          if (prop.param().find("xml") != std::string::npos)
            return AddMultiInfo(CGUIInfo(window_bool.val, 0, prop.param()));
          int winID = prop.param().empty() ? WINDOW_INVALID
                                           : CWindowTranslator::TranslateWindow(prop.param());
          return AddMultiInfo(CGUIInfo(window_bool.val, winID, 0));
        }
      }
    }
    else if (cat.Name() == "control")
    {
      for (const auto& control_label : control_labels)
      {
        if (prop.Name() == control_label.str)
        { //! @todo The parameter for these should really be on the first not the second property
          int controlID = atoi(prop.param().c_str());
          if (controlID)
            return AddMultiInfo(CGUIInfo(control_label.val, controlID, 0));
          return 0;
        }
      }
    }
    else if (cat.Name() == "controlgroup" && prop.Name() == "hasfocus")
    {
      int groupID = atoi(cat.param().c_str());
      if (groupID)
        return AddMultiInfo(
            CGUIInfo(CONTROL_GROUP_HAS_FOCUS, groupID, atoi(prop.param(0).c_str())));
    }
    else if (cat.Name() == "playlist")
    {
      int ret = -1;
      for (const auto& i : playlist)
      {
        if (prop.Name() == i.str)
        {
          ret = i.val;
          break;
        }
      }
      if (ret >= 0)
      {
        if (prop.num_params() <= 0)
          return ret;
        else
        {
          PLAYLIST::Id playlistid = PLAYLIST::Id::TYPE_NONE;
          if (StringUtils::EqualsNoCase(prop.param(), "video"))
            playlistid = PLAYLIST::Id::TYPE_VIDEO;
          else if (StringUtils::EqualsNoCase(prop.param(), "music"))
            playlistid = PLAYLIST::Id::TYPE_MUSIC;

          if (playlistid != PLAYLIST::Id::TYPE_NONE)
            return AddMultiInfo(CGUIInfo(ret, static_cast<int>(playlistid), 1));
        }
      }
    }
    else if (cat.Name() == "pvr")
    {
      for (const auto& i : pvr)
      {
        if (prop.Name() == i.str)
          return i.val;
      }
      for (const auto& pvr_time : pvr_times)
      {
        if (prop.Name() == pvr_time.str)
          return AddMultiInfo(CGUIInfo(pvr_time.val, TranslateTimeFormat(prop.param())));
      }
    }
    else if (cat.Name() == "rds")
    {
      if (prop.Name() == "getline")
        return AddMultiInfo(CGUIInfo(RDS_GET_RADIOTEXT_LINE, atoi(prop.param(0).c_str())));

      for (const auto& rd : rds)
      {
        if (prop.Name() == rd.str)
          return rd.val;
      }
    }
  }
  else if (info.size() == 3 || info.size() == 4)
  {
    if (info[0].Name() == "system" && info[1].Name() == "platform")
    { //! @todo replace with a single system.platform
      std::string platform = info[2].Name();
      if (platform == "linux")
        return SYSTEM_PLATFORM_LINUX;
      else if (platform == "windows")
        return SYSTEM_PLATFORM_WINDOWS;
      else if (platform == "uwp")
        return SYSTEM_PLATFORM_UWP;
      else if (platform == "darwin")
        return SYSTEM_PLATFORM_DARWIN;
      else if (platform == "osx")
        return SYSTEM_PLATFORM_DARWIN_OSX;
      else if (platform == "ios")
        return SYSTEM_PLATFORM_DARWIN_IOS;
      else if (platform == "tvos")
        return SYSTEM_PLATFORM_DARWIN_TVOS;
      else if (platform == "android")
        return SYSTEM_PLATFORM_ANDROID;
      else if (platform == "webos")
        return SYSTEM_PLATFORM_WEBOS;
    }
    if (info[0].Name() == "musicplayer")
    { //! @todo these two don't allow duration(foo) and also don't allow more than this number of levels...
      if (info[1].Name() == "position")
      {
        int position = atoi(info[1].param().c_str());
        int value = TranslateMusicPlayerString(info[2].Name()); // musicplayer.position(foo).bar
        return AddMultiInfo(CGUIInfo(value, 2, position)); // 2 => absolute (0 used for not set)
      }
      else if (info[1].Name() == "offset")
      {
        int position = atoi(info[1].param().c_str());
        int value = TranslateMusicPlayerString(info[2].Name()); // musicplayer.offset(foo).bar
        return AddMultiInfo(CGUIInfo(value, 1, position)); // 1 => relative
      }
    }
    else if (info[0].Name() == "videoplayer")
    { //! @todo these two don't allow duration(foo) and also don't allow more than this number of levels...
      if (info[1].Name() == "position")
      {
        int position = atoi(info[1].param().c_str());
        int value = TranslateVideoPlayerString(info[2].Name()); // videoplayer.position(foo).bar
        // additional param for the requested infolabel, e.g. VideoPlayer.Position(1).Art(poster): art is the value, poster is the param
        const std::string& param = info[2].param();
        return AddMultiInfo(
            CGUIInfo(value, 2, position, param)); // 2 => absolute (0 used for not set)
      }
      else if (info[1].Name() == "offset")
      {
        int position = atoi(info[1].param().c_str());
        int value = TranslateVideoPlayerString(info[2].Name()); // videoplayer.offset(foo).bar
        // additional param for the requested infolabel, e.g. VideoPlayer.Offset(1).Art(poster): art is the value, poster is the param
        const std::string& param = info[2].param();
        return AddMultiInfo(CGUIInfo(value, 1, position, param)); // 1 => relative
      }
    }
    else if (info[0].Name() == "player")
    { //! @todo these two don't allow duration(foo) and also don't allow more than this number of levels...
      if (info[1].Name() == "position")
      {
        int position = atoi(info[1].param().c_str());
        int value = TranslatePlayerString(info[2].Name()); // player.position(foo).bar
        return AddMultiInfo(CGUIInfo(value, 2, position)); // 2 => absolute (0 used for not set)
      }
      else if (info[1].Name() == "offset")
      {
        int position = atoi(info[1].param().c_str());
        int value = TranslatePlayerString(info[2].Name()); // player.offset(foo).bar
        return AddMultiInfo(CGUIInfo(value, 1, position)); // 1 => relative
      }
    }
    else if (info[0].Name() == "container")
    {
      if (info[1].Name() == "listitem" || info[1].Name() == "listitemposition" ||
          info[1].Name() == "listitemabsolute" || info[1].Name() == "listitemnowrap")
      {
        int id = atoi(info[0].param().c_str());
        int ret = TranslateListItem(info[1], info[2], id, true);
        if (ret)
          listItemDependent = true;
        return ret;
      }
    }
    else if (info[0].Name() == "control")
    {
      const Property& prop = info[1];
      for (const auto& control_label : control_labels)
      {
        if (prop.Name() == control_label.str)
        { //! @todo The parameter for these should really be on the first not the second property
          int controlID = atoi(prop.param().c_str());
          if (controlID)
            return AddMultiInfo(
                CGUIInfo(control_label.val, controlID, atoi(info[2].param(0).c_str())));
          return 0;
        }
      }
    }
  }

  return 0;
}

int CGUIInfoManager::TranslateListItem(const Property& cat,
                                       const Property& prop,
                                       int id,
                                       bool container)
{
  int ret = 0;
  std::string data3;
  int data4 = 0;
  if (prop.num_params() == 1)
  {
    // special case: map 'property(fanart_image)' to 'art(fanart)'
    if (prop.Name() == "property" && StringUtils::EqualsNoCase(prop.param(), "fanart_image"))
    {
      ret = LISTITEM_ART;
      data3 = "fanart";
    }
    else if (prop.Name() == "property" || prop.Name() == "art" || prop.Name() == "rating" ||
             prop.Name() == "votes" || prop.Name() == "ratingandvotes" || prop.Name() == "uniqueid")
    {
      data3 = prop.param();
    }
    else if (prop.Name() == "cast" || prop.Name() == "castandrole" || prop.Name() == "director" ||
             prop.Name() == "writer" || prop.Name() == "genre" || prop.Name() == "nextgenre")
    {
      data3 = TranslateListSeparator(prop.param());
    }
    else if (prop.Name() == "duration" || prop.Name() == "nextduration")
    {
      data4 = TranslateTimeFormat(prop.param());
    }
    else if (prop.Name() == "audiochannels" || prop.Name() == "musicchannels" ||
             prop.Name() == "firstaudiochannels")
    {
      data3 = prop.param();
    }
  }

  if (ret == 0)
  {
    for (const auto& listitem_label : listitem_labels) // these ones don't have or need an id
    {
      if (prop.Name() == listitem_label.str)
      {
        ret = listitem_label.val;
        break;
      }
    }
  }

  if (ret)
  {
    int offset = std::atoi(cat.param().c_str());

    int flags = 0;
    if (cat.Name() == "listitem")
      flags = INFOFLAG_LISTITEM_WRAP;
    else if (cat.Name() == "listitemposition")
      flags = INFOFLAG_LISTITEM_POSITION;
    else if (cat.Name() == "listitemabsolute")
      flags = INFOFLAG_LISTITEM_ABSOLUTE;
    else if (cat.Name() == "listitemnowrap")
      flags = INFOFLAG_LISTITEM_NOWRAP;

    if (container)
      flags |= INFOFLAG_LISTITEM_CONTAINER;

    return AddMultiInfo(CGUIInfo(ret, id, offset, flags, data3, data4));
  }

  return 0;
}

int CGUIInfoManager::TranslateMusicPlayerString(std::string_view info) const
{
  for (const auto& i : musicplayer)
  {
    if (info == i.str)
      return i.val;
  }
  return 0;
}

int CGUIInfoManager::TranslateVideoPlayerString(std::string_view info) const
{
  for (const auto& i : videoplayer)
  {
    if (info == i.str)
      return i.val;
  }
  return 0;
}

int CGUIInfoManager::TranslatePlayerString(std::string_view info) const
{
  for (const auto& i : player_labels)
  {
    if (info == i.str)
      return i.val;
  }
  return 0;
}

TIME_FORMAT CGUIInfoManager::TranslateTimeFormat(const std::string& format)
{
  if (format.empty())
    return TIME_FORMAT_GUESS;
  else if (StringUtils::EqualsNoCase(format, "hh"))
    return TIME_FORMAT_HH;
  else if (StringUtils::EqualsNoCase(format, "mm"))
    return TIME_FORMAT_MM;
  else if (StringUtils::EqualsNoCase(format, "ss"))
    return TIME_FORMAT_SS;
  else if (StringUtils::EqualsNoCase(format, "hh:mm"))
    return TIME_FORMAT_HH_MM;
  else if (StringUtils::EqualsNoCase(format, "mm:ss"))
    return TIME_FORMAT_MM_SS;
  else if (StringUtils::EqualsNoCase(format, "hh:mm:ss"))
    return TIME_FORMAT_HH_MM_SS;
  else if (StringUtils::EqualsNoCase(format, "hh:mm:ss xx"))
    return TIME_FORMAT_HH_MM_SS_XX;
  else if (StringUtils::EqualsNoCase(format, "h"))
    return TIME_FORMAT_H;
  else if (StringUtils::EqualsNoCase(format, "m"))
    return TIME_FORMAT_M;
  else if (StringUtils::EqualsNoCase(format, "h:mm:ss"))
    return TIME_FORMAT_H_MM_SS;
  else if (StringUtils::EqualsNoCase(format, "h:mm:ss xx"))
    return TIME_FORMAT_H_MM_SS_XX;
  else if (StringUtils::EqualsNoCase(format, "xx"))
    return TIME_FORMAT_XX;
  else if (StringUtils::EqualsNoCase(format, "secs"))
    return TIME_FORMAT_SECS;
  else if (StringUtils::EqualsNoCase(format, "mins"))
    return TIME_FORMAT_MINS;
  else if (StringUtils::EqualsNoCase(format, "hours"))
    return TIME_FORMAT_HOURS;
  return TIME_FORMAT_GUESS;
}

std::string CGUIInfoManager::GetLabel(int info, int contextWindow, std::string* fallback) const
{
  if (info >= CONDITIONAL_LABEL_START && info <= CONDITIONAL_LABEL_END)
  {
    return GetSkinVariableString(info, contextWindow, false);
  }
  else if (info >= MULTI_INFO_START && info <= MULTI_INFO_END)
  {
    return GetMultiInfoLabel(m_multiInfo[info - MULTI_INFO_START], contextWindow);
  }
  else if (info >= LISTITEM_START && info <= LISTITEM_END)
  {
    const std::shared_ptr<CGUIListItem> item = GUIINFO::GetCurrentListItem(contextWindow);
    if (item && item->IsFileItem())
      return GetItemLabel(static_cast<CFileItem*>(item.get()), contextWindow, info, fallback);
  }

  std::string strLabel;
  m_infoProviders.GetLabel(strLabel, m_currentFile.get(), contextWindow, CGUIInfo(info), fallback);
  return strLabel;
}

bool CGUIInfoManager::GetInt(int& value,
                             int info,
                             int contextWindow,
                             const CGUIListItem* item /* = nullptr */) const
{
  if (info >= MULTI_INFO_START && info <= MULTI_INFO_END)
  {
    return GetMultiInfoInt(value, m_multiInfo[info - MULTI_INFO_START], contextWindow, item);
  }
  else if (info >= LISTITEM_START && info <= LISTITEM_END)
  {
    std::shared_ptr<CGUIListItem> itemPtr;
    if (!item)
    {
      itemPtr = GUIINFO::GetCurrentListItem(contextWindow);
      item = itemPtr.get();
    }
    return GetItemInt(value, item, contextWindow, info);
  }

  value = 0;
  return m_infoProviders.GetInt(value, m_currentFile.get(), contextWindow, CGUIInfo(info));
}

INFO::InfoPtr CGUIInfoManager::Register(const std::string& expression, int context)
{
  std::string condition(CGUIInfoLabel::ReplaceLocalize(expression));
  StringUtils::Trim(condition);

  if (condition.empty())
    return INFO::InfoPtr();

  std::unique_lock lock(m_critInfo);
  std::pair<INFOBOOLTYPE::iterator, bool> res;

  if (condition.find_first_of("|+[]!") != std::string::npos)
    res = m_bools.insert(std::make_shared<InfoExpression>(condition, context, m_refreshCounter));
  else
    res = m_bools.insert(std::make_shared<InfoSingle>(condition, context, m_refreshCounter));

  if (res.second)
    res.first->get()->Initialize(this);

  return *(res.first);
}

void CGUIInfoManager::UnRegister(const INFO::InfoPtr& expression)
{
  std::unique_lock lock(m_critInfo);
  m_bools.erase(expression);
}

bool CGUIInfoManager::EvaluateBool(const std::string& expression,
                                   int contextWindow /* = 0 */,
                                   const std::shared_ptr<CGUIListItem>& item /* = nullptr */)
{
  INFO::InfoPtr info = Register(expression, contextWindow);
  if (info)
    return info->Get(contextWindow, item.get());
  return false;
}

bool CGUIInfoManager::GetBool(int condition1, int contextWindow, const CGUIListItem* item)
{
  bool bReturn = false;
  int condition = std::abs(condition1);

  if (condition >= LISTITEM_START && condition < LISTITEM_END)
  {
    std::shared_ptr<CGUIListItem> itemPtr;
    if (!item)
    {
      itemPtr = GUIINFO::GetCurrentListItem(contextWindow);
      item = itemPtr.get();
    }
    bReturn = GetItemBool(item, contextWindow, condition);
  }
  else if (condition >= MULTI_INFO_START && condition <= MULTI_INFO_END)
  {
    bReturn = GetMultiInfoBool(m_multiInfo[condition - MULTI_INFO_START], contextWindow, item);
  }
  else if (!m_infoProviders.GetBool(bReturn, m_currentFile.get(), contextWindow,
                                    CGUIInfo(condition)))
  {
    // default: use integer value different from 0 as true
    int val;
    bReturn = GetInt(val, condition, DEFAULT_CONTEXT) && val != 0;
  }

  return (condition1 < 0) ? !bReturn : bReturn;
}

bool CGUIInfoManager::GetMultiInfoBool(const CGUIInfo& info,
                                       int contextWindow,
                                       const CGUIListItem* item)
{
  bool bReturn = false;
  int condition = std::abs(info.GetInfo());

  if (condition >= LISTITEM_START && condition <= LISTITEM_END)
  {
    std::shared_ptr<CGUIListItem> itemPtr;
    if (!item)
    {
      itemPtr = GUIINFO::GetCurrentListItem(contextWindow, info.GetData1(), info.GetData2(),
                                            info.GetInfoFlag());
      item = itemPtr.get();
    }
    if (item)
    {
      if (condition == LISTITEM_PROPERTY)
      {
        if (item->HasProperty(info.GetData3()))
          bReturn = item->GetProperty(info.GetData3()).asBoolean();
      }
      else
        bReturn = GetItemBool(item, contextWindow, condition);
    }
    else
    {
      bReturn = false;
    }
  }
  else if (!m_infoProviders.GetBool(bReturn, m_currentFile.get(), contextWindow, info))
  {
    switch (condition)
    {
      case STRING_IS_EMPTY:
        // note: Get*Image() falls back to Get*Label(), so this should cover all of them
        if (item && item->IsFileItem() && IsListItemInfo(info.GetData1()))
          bReturn = GetItemImage(item, contextWindow, info.GetData1()).empty();
        else
          bReturn = GetImage(info.GetData1(), contextWindow).empty();
        break;
      case STRING_STARTS_WITH:
      case STRING_ENDS_WITH:
      case STRING_CONTAINS:
      case STRING_IS_EQUAL:
      {
        std::string compare;
        if (info.GetData2() < 0) // info labels are stored with negative numbers
        {
          int info2 = -info.GetData2();
          std::shared_ptr<CGUIListItem> item2;

          if (IsListItemInfo(info2))
          {
            int iResolvedInfo2 = ResolveMultiInfo(info2);
            if (iResolvedInfo2 != 0)
            {
              const GUIINFO::CGUIInfo& resolvedInfo2 =
                  m_multiInfo[iResolvedInfo2 - MULTI_INFO_START];
              if (resolvedInfo2.GetInfoFlag() & INFOFLAG_LISTITEM_CONTAINER)
                item2 = GUIINFO::GetCurrentListItem(
                    contextWindow, resolvedInfo2.GetData1()); // data1 contains the container id
            }
          }

          if (item2 && item2->IsFileItem())
            compare = GetItemImage(item2.get(), contextWindow, info2);
          else if (item && item->IsFileItem())
            compare = GetItemImage(item, contextWindow, info2);
          else
            compare = GetImage(info2, contextWindow);
        }
        else if (!info.GetData3().empty())
        { // conditional string
          compare = info.GetData3();
        }
        StringUtils::ToLower(compare);

        std::string label;
        if (item && item->IsFileItem() && IsListItemInfo(info.GetData1()))
          label = GetItemImage(item, contextWindow, info.GetData1());
        else
          label = GetImage(info.GetData1(), contextWindow);
        StringUtils::ToLower(label);

        if (condition == STRING_STARTS_WITH)
          bReturn = StringUtils::StartsWith(label, compare);
        else if (condition == STRING_ENDS_WITH)
          bReturn = StringUtils::EndsWith(label, compare);
        else if (condition == STRING_CONTAINS)
          bReturn = label.find(compare) != std::string::npos;
        else
          bReturn = StringUtils::EqualsNoCase(label, compare);
        break;
      }
      case INTEGER_IS_EQUAL:
      case INTEGER_GREATER_THAN:
      case INTEGER_GREATER_OR_EQUAL:
      case INTEGER_LESS_THAN:
      case INTEGER_LESS_OR_EQUAL:
      case INTEGER_EVEN:
      case INTEGER_ODD:
      {
        auto getIntValue = [this, &item, &contextWindow](int infoNum)
        {
          int intValue = 0;
          if (!GetInt(intValue, infoNum, contextWindow, item))
          {
            std::string value;
            if (item && item->IsFileItem() && IsListItemInfo(infoNum))
              value = GetItemImage(item, contextWindow, infoNum);
            else
              value = GetImage(infoNum, contextWindow);

            // Handle the case when a value contains time separator (:). This makes Integer.IsGreater
            // useful for Player.Time* members without adding a separate set of members returning time in seconds
            if (value.find_first_of(':') != std::string::npos)
              intValue = StringUtils::TimeStringToSeconds(value);
            else
              std::from_chars(value.data(), value.data() + value.size(), intValue);
          }
          return intValue;
        };

        int leftIntValue = getIntValue(info.GetData1());
        int rightIntValue = getIntValue(info.GetData2());

        // compare
        if (condition == INTEGER_IS_EQUAL)
          bReturn = leftIntValue == rightIntValue;
        else if (condition == INTEGER_GREATER_THAN)
          bReturn = leftIntValue > rightIntValue;
        else if (condition == INTEGER_GREATER_OR_EQUAL)
          bReturn = leftIntValue >= rightIntValue;
        else if (condition == INTEGER_LESS_THAN)
          bReturn = leftIntValue < rightIntValue;
        else if (condition == INTEGER_LESS_OR_EQUAL)
          bReturn = leftIntValue <= rightIntValue;
        else if (condition == INTEGER_EVEN)
          bReturn = leftIntValue % 2 == 0;
        else if (condition == INTEGER_ODD)
          bReturn = leftIntValue % 2 != 0;
        break;
      }
      default:
        break;
    }
  }
  return (info.GetInfo() < 0) ? !bReturn : bReturn;
}

bool CGUIInfoManager::GetMultiInfoInt(int& value,
                                      const CGUIInfo& info,
                                      int contextWindow,
                                      const CGUIListItem* item) const
{
  if (info.GetInfo() == INTEGER_VALUEOF)
  {
    value = info.GetData1();
    return true;
  }
  else if (info.GetInfo() >= LISTITEM_START && info.GetInfo() <= LISTITEM_END)
  {
    std::shared_ptr<CGUIListItem> itemPtr;
    if (!item)
    {
      itemPtr = GUIINFO::GetCurrentListItem(contextWindow, info.GetData1(), info.GetData2(),
                                            info.GetInfoFlag());
      item = itemPtr.get();
    }
    if (item)
    {
      if (info.GetInfo() == LISTITEM_PROPERTY)
      {
        if (item->HasProperty(info.GetData3()))
        {
          value = item->GetProperty(info.GetData3()).asInteger();
          return true;
        }
        return false;
      }
      else
        return GetItemInt(value, item, contextWindow, info.GetInfo());
    }
    else
    {
      return false;
    }
  }

  return m_infoProviders.GetInt(value, m_currentFile.get(), contextWindow, info);
}

std::string CGUIInfoManager::GetMultiInfoLabel(const CGUIInfo& constinfo,
                                               int contextWindow,
                                               std::string* fallback) const
{
  CGUIInfo info(constinfo);

  if (info.GetInfo() >= LISTITEM_START && info.GetInfo() <= LISTITEM_END)
  {
    const std::shared_ptr<CGUIListItem> item = GUIINFO::GetCurrentListItem(
        contextWindow, info.GetData1(), info.GetData2(), info.GetInfoFlag());
    if (item)
    {
      // Image prioritizes images over labels (in the case of music item ratings for instance)
      return GetMultiInfoItemImage(dynamic_cast<CFileItem*>(item.get()), contextWindow, info,
                                   fallback);
    }
    else
    {
      return std::string();
    }
  }
  else if (info.GetInfo() == SYSTEM_ADDON_TITLE || info.GetInfo() == SYSTEM_ADDON_ICON ||
           info.GetInfo() == SYSTEM_ADDON_VERSION)
  {
    if (info.GetData2() == 0)
    {
      // resolve the addon id
      const std::string addonId = GetLabel(info.GetData1(), contextWindow);
      info = CGUIInfo(info.GetInfo(), addonId);
    }
  }

  std::string strValue;
  m_infoProviders.GetLabel(strValue, m_currentFile.get(), contextWindow, info, fallback);
  return strValue;
}

/// \brief Obtains the filename of the image to show from whichever subsystem is needed
std::string CGUIInfoManager::GetImage(int info, int contextWindow, std::string* fallback)
{
  if (info >= CONDITIONAL_LABEL_START && info <= CONDITIONAL_LABEL_END)
  {
    return GetSkinVariableString(info, contextWindow, true);
  }
  else if (info >= MULTI_INFO_START && info <= MULTI_INFO_END)
  {
    return GetMultiInfoLabel(m_multiInfo[info - MULTI_INFO_START], contextWindow, fallback);
  }
  else if (info == LISTITEM_THUMB || info == LISTITEM_ICON || info == LISTITEM_ACTUAL_ICON ||
           info == LISTITEM_OVERLAY || info == LISTITEM_ART)
  {
    const std::shared_ptr<CGUIListItem> item = GUIINFO::GetCurrentListItem(contextWindow);
    if (item && item->IsFileItem())
      return GetItemImage(item.get(), contextWindow, info, fallback);
  }

  return GetLabel(info, contextWindow, fallback);
}

void CGUIInfoManager::ResetCurrentItem()
{
  m_currentFile = std::make_unique<CFileItem>();
  m_infoProviders.InitCurrentItem(nullptr);
}

void CGUIInfoManager::UpdateCurrentItem(const CFileItem& item)
{
  m_currentFile->UpdateInfo(item);
}

void CGUIInfoManager::SetCurrentItem(const CFileItem& item)
{
  *m_currentFile = item;
  ART::FillInDefaultIcon(*m_currentFile);

  m_infoProviders.InitCurrentItem(m_currentFile.get());

  CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Info, "OnChanged");
}

void CGUIInfoManager::SetCurrentAlbumThumb(const std::string& thumbFileName)
{
  if (CFileUtils::Exists(thumbFileName))
    m_currentFile->SetArt("thumb", thumbFileName);
  else
  {
    m_currentFile->SetArt("thumb", "");
    ART::FillInDefaultIcon(*m_currentFile);
  }
}

void CGUIInfoManager::Clear()
{
  std::unique_lock lock(m_critInfo);
  m_skinVariableStrings.clear();

  /*
    Erase any info bools that are unused. We do this repeatedly as each run
    will remove those bools that are no longer dependencies of other bools
    in the vector.
   */
  INFOBOOLTYPE swapList(&InfoBoolComparator);
  do
  {
    swapList.clear();
    for (auto& item : m_bools)
      if (item.use_count() > 1)
        swapList.insert(item);
    m_bools.swap(swapList);
  } while (swapList.size() != m_bools.size());

  // log which ones are used - they should all be gone by now
  for (const auto& infoBool : m_bools)
    CLog::Log(LOGDEBUG, "Infobool '{}' still used by {} instances", infoBool->GetExpression(),
              infoBool.use_count());
}

void CGUIInfoManager::UpdateAVInfo() const
{
  if (CServiceBroker::GetDataCacheCore().HasAVInfoChanges())
  {
    VideoStreamInfo video;
    AudioStreamInfo audio;
    SubtitleStreamInfo subtitle;

    auto& components = CServiceBroker::GetAppComponents();
    const auto appPlayer = components.GetComponent<CApplicationPlayer>();
    appPlayer->GetVideoStreamInfo(CURRENT_STREAM, video);
    appPlayer->GetAudioStreamInfo(CURRENT_STREAM, audio);
    appPlayer->GetSubtitleStreamInfo(CURRENT_STREAM, subtitle);

    m_infoProviders.UpdateAVInfo(audio, video, subtitle);
  }
}

int CGUIInfoManager::AddMultiInfo(const CGUIInfo& info)
{
  // check to see if we have this info already
  for (unsigned int i = 0; i < m_multiInfo.size(); ++i)
    if (m_multiInfo[i] == info)
      return static_cast<int>(i) + MULTI_INFO_START;
  // return the new offset
  m_multiInfo.emplace_back(info);
  int id = static_cast<int>(m_multiInfo.size()) + MULTI_INFO_START - 1;
  if (id > MULTI_INFO_END)
    CLog::LogF(LOGERROR, "Too many multiinfo bool/labels in this skin");
  return id;
}

int CGUIInfoManager::ResolveMultiInfo(int info) const
{
  int iLastInfo = 0;

  int iResolvedInfo = info;
  while (iResolvedInfo >= MULTI_INFO_START && iResolvedInfo <= MULTI_INFO_END)
  {
    iLastInfo = iResolvedInfo;
    iResolvedInfo = m_multiInfo[iResolvedInfo - MULTI_INFO_START].GetInfo();
  }

  return iLastInfo;
}

bool CGUIInfoManager::IsListItemInfo(int info) const
{
  int iResolvedInfo = info;
  while (iResolvedInfo >= MULTI_INFO_START && iResolvedInfo <= MULTI_INFO_END)
    iResolvedInfo = m_multiInfo[iResolvedInfo - MULTI_INFO_START].GetInfo();

  return (iResolvedInfo >= LISTITEM_START && iResolvedInfo <= LISTITEM_END);
}

bool CGUIInfoManager::GetItemInt(int& value,
                                 const CGUIListItem* item,
                                 int contextWindow,
                                 int info) const
{
  value = 0;

  if (!item)
    return false;

  return m_infoProviders.GetInt(value, item, contextWindow, CGUIInfo(info));
}

std::string CGUIInfoManager::GetItemLabel(const CFileItem* item,
                                          int contextWindow,
                                          int info,
                                          std::string* fallback /* = nullptr */) const
{
  return GetMultiInfoItemLabel(item, contextWindow, CGUIInfo(info), fallback);
}

std::string CGUIInfoManager::GetMultiInfoItemLabel(const CFileItem* item,
                                                   int contextWindow,
                                                   const CGUIInfo& info,
                                                   std::string* fallback /* = nullptr */) const
{
  if (!item)
    return std::string();

  std::string value;

  if (info.GetInfo() >= CONDITIONAL_LABEL_START && info.GetInfo() <= CONDITIONAL_LABEL_END)
  {
    return GetSkinVariableString(info.GetInfo(), contextWindow, false, item);
  }
  else if (info.GetInfo() >= MULTI_INFO_START && info.GetInfo() <= MULTI_INFO_END)
  {
    return GetMultiInfoItemLabel(item, contextWindow,
                                 m_multiInfo[info.GetInfo() - MULTI_INFO_START], fallback);
  }
  else if (!m_infoProviders.GetLabel(value, item, contextWindow, info, fallback))
  {
    switch (info.GetInfo())
    {
      case LISTITEM_PROPERTY:
        return item->GetProperty(info.GetData3()).asString();
      case LISTITEM_LABEL:
        return item->GetLabel();
      case LISTITEM_LABEL2:
        return item->GetLabel2();
      case LISTITEM_FILENAME:
      case LISTITEM_FILE_EXTENSION:
      case LISTITEM_FILENAME_NO_EXTENSION:
      {
        std::string strFile = URIUtils::GetFileName(item->GetPath());
        if (info.GetInfo() == LISTITEM_FILE_EXTENSION)
        {
          std::string strExtension = URIUtils::GetExtension(strFile);
          return StringUtils::TrimLeft(strExtension, ".");
        }
        else if (info.GetInfo() == LISTITEM_FILENAME_NO_EXTENSION)
        {
          URIUtils::RemoveExtension(strFile);
        }
        return strFile;
      }
      case LISTITEM_DATE:
      {
        const CDateTime& dateTime{item->GetDateTime()};
        if (dateTime.IsValid())
          return dateTime.GetAsLocalizedDate();
        break;
      }
      case LISTITEM_DATETIME:
      {
        const CDateTime& dateTime{item->GetDateTime()};
        if (dateTime.IsValid())
          return dateTime.GetAsLocalizedDateTime();
        break;
      }
      case LISTITEM_SIZE:
        if (!item->IsFolder() || item->GetSize())
          return StringUtils::SizeToString(item->GetSize());
        break;
      case LISTITEM_PROGRAM_COUNT:
        return std::to_string(item->GetProgramCount());
      case LISTITEM_ACTUAL_ICON:
        return item->GetArt("icon");
      case LISTITEM_ICON:
      {
        std::string strThumb = item->GetThumbHideIfUnwatched(item);
        if (strThumb.empty())
          strThumb = item->GetArt("icon");
        if (fallback)
          *fallback = item->GetArt("icon");
        return strThumb;
      }
      case LISTITEM_ART:
        return item->GetArt(info.GetData3());
      case LISTITEM_OVERLAY:
        return item->GetOverlayImage();
      case LISTITEM_THUMB:
        return item->GetThumbHideIfUnwatched(item);
      case LISTITEM_FOLDERPATH:
        return item->GetURL().GetWithoutUserDetails();
      case LISTITEM_FOLDERNAME:
      case LISTITEM_PATH:
      {
        std::string path;
        URIUtils::GetParentPath(item->GetPath(), path);
        path = CURL(path).GetWithoutUserDetails();
        if (info.GetInfo() == LISTITEM_FOLDERNAME)
        {
          URIUtils::RemoveSlashAtEnd(path);
          path = URIUtils::GetFileName(path);
        }
        return path;
      }
      case LISTITEM_FILENAME_AND_PATH:
      {
        std::string path = item->GetPath();
        path = CURL(path).GetWithoutUserDetails();
        return path;
      }
      case LISTITEM_SORT_LETTER:
      {
        std::string letter;
        std::wstring character(1, item->GetSortLabel()[0]);
        StringUtils::ToUpper(character);
        CCharsetConverter::wToUTF8(character, letter);
        return letter;
      }
      case LISTITEM_STARTTIME:
      {
        const CDateTime& dateTime{item->GetDateTime()};
        if (dateTime.IsValid())
          return dateTime.GetAsLocalizedTime("", false);
        break;
      }
      case LISTITEM_STARTDATE:
      {
        const CDateTime& dateTime{item->GetDateTime()};
        if (dateTime.IsValid())
          return dateTime.GetAsLocalizedDate(true);
        break;
      }
      case LISTITEM_CURRENTITEM:
        return std::to_string(item->GetCurrentItem());
      default:
        break;
    }
  }

  return value;
}

std::string CGUIInfoManager::GetItemImage(const CGUIListItem* item,
                                          int contextWindow,
                                          int info,
                                          std::string* fallback /*= nullptr*/) const
{
  if (!item || !item->IsFileItem())
    return std::string();

  return GetMultiInfoItemImage(static_cast<const CFileItem*>(item), contextWindow, CGUIInfo(info),
                               fallback);
}

std::string CGUIInfoManager::GetMultiInfoItemImage(const CFileItem* item,
                                                   int contextWindow,
                                                   const CGUIInfo& info,
                                                   std::string* fallback /*= nullptr*/) const
{
  if (info.GetInfo() >= CONDITIONAL_LABEL_START && info.GetInfo() <= CONDITIONAL_LABEL_END)
  {
    return GetSkinVariableString(info.GetInfo(), contextWindow, true, item);
  }
  else if (info.GetInfo() >= MULTI_INFO_START && info.GetInfo() <= MULTI_INFO_END)
  {
    return GetMultiInfoItemImage(item, contextWindow,
                                 m_multiInfo[info.GetInfo() - MULTI_INFO_START], fallback);
  }

  return GetMultiInfoItemLabel(item, contextWindow, info, fallback);
}

bool CGUIInfoManager::GetItemBool(const CGUIListItem* item, int contextWindow, int condition) const
{
  if (!item)
    return false;

  bool value = false;
  if (!m_infoProviders.GetBool(value, item, contextWindow, CGUIInfo(condition)))
  {
    switch (condition)
    {
      case LISTITEM_ISSELECTED:
        return item->IsSelected();
      case LISTITEM_IS_FOLDER:
        return item->IsFolder();
      case LISTITEM_IS_PARENTFOLDER:
      {
        if (item->IsFileItem())
        {
          const auto* pItem{static_cast<const CFileItem*>(item)};
          return pItem->IsParentFolder();
        }
        break;
      }
      default:
        break;
    }
  }

  return value;
}

void CGUIInfoManager::ResetCache()
{
  // mark our infobools as dirty
  std::unique_lock lock(m_critInfo);
  ++m_refreshCounter;
}

void CGUIInfoManager::SetCurrentVideoTag(const CVideoInfoTag& tag)
{
  m_currentFile->SetFromVideoInfoTag(tag);
  m_currentFile->SetStartOffset(0);

  CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Info, "OnChanged");
}

void CGUIInfoManager::SetCurrentSongTag(const MUSIC_INFO::CMusicInfoTag& tag)
{
  m_currentFile->SetFromMusicInfoTag(tag);
  m_currentFile->SetStartOffset(0);

  CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Info, "OnChanged");
}

const MUSIC_INFO::CMusicInfoTag* CGUIInfoManager::GetCurrentSongTag() const
{
  if (m_currentFile->HasMusicInfoTag())
    return m_currentFile->GetMusicInfoTag();

  return nullptr;
}

const CVideoInfoTag* CGUIInfoManager::GetCurrentMovieTag() const
{
  if (m_currentFile->HasVideoInfoTag())
    return m_currentFile->GetVideoInfoTag();

  return nullptr;
}

const KODI::GAME::CGameInfoTag* CGUIInfoManager::GetCurrentGameTag() const
{
  if (m_currentFile->HasGameInfoTag())
    return m_currentFile->GetGameInfoTag();

  return nullptr;
}

int CGUIInfoManager::RegisterSkinVariableString(const CSkinVariableString* info)
{
  if (!info)
    return 0;

  std::unique_lock lock(m_critInfo);
  m_skinVariableStrings.emplace_back(*info);
  delete info;
  return CONDITIONAL_LABEL_START + m_skinVariableStrings.size() - 1;
}

int CGUIInfoManager::TranslateSkinVariableString(const std::string& name, int context)
{
  for (std::vector<CSkinVariableString>::const_iterator it = m_skinVariableStrings.begin();
       it != m_skinVariableStrings.end(); ++it)
  {
    if (StringUtils::EqualsNoCase(it->GetName(), name) && it->GetContext() == context)
      return it - m_skinVariableStrings.begin() + CONDITIONAL_LABEL_START;
  }
  return 0;
}

std::string CGUIInfoManager::GetSkinVariableString(int info,
                                                   int contextWindow,
                                                   bool preferImage /*= false*/,
                                                   const CGUIListItem* item /*= nullptr*/) const
{
  info -= CONDITIONAL_LABEL_START;
  if (info >= 0 && info < static_cast<int>(m_skinVariableStrings.size()))
    return m_skinVariableStrings[info].GetValue(contextWindow, preferImage, item);

  return "";
}

bool CGUIInfoManager::ConditionsChangedValues(const std::map<INFO::InfoPtr, bool>& map) const
{
  return std::ranges::any_of(map,
                             [](const auto& entry)
                             {
                               const auto& [info, value] = entry;
                               return info->Get(INFO::DEFAULT_CONTEXT) != value;
                             });
}

int CGUIInfoManager::GetMessageMask()
{
  return TMSG_MASK_GUIINFOMANAGER;
}

void CGUIInfoManager::OnApplicationMessage(KODI::MESSAGING::ThreadMessage* pMsg)
{
  switch (pMsg->dwMessage)
  {
    case TMSG_GUI_INFOLABEL:
    {
      if (pMsg->lpVoid)
      {
        auto infoLabels = static_cast<std::vector<std::string>*>(pMsg->lpVoid);
        for (const auto& param : pMsg->params)
          infoLabels->emplace_back(GetLabel(TranslateString(param), DEFAULT_CONTEXT));
      }
    }
    break;

    case TMSG_GUI_INFOBOOL:
    {
      if (pMsg->lpVoid)
      {
        auto infoLabels = static_cast<std::vector<bool>*>(pMsg->lpVoid);
        for (const auto& param : pMsg->params)
          infoLabels->push_back(EvaluateBool(param, DEFAULT_CONTEXT));
      }
    }
    break;

    case TMSG_UPDATE_CURRENT_ITEM:
    {
      auto* item{static_cast<CFileItem*>(pMsg->lpVoid)};
      if (!item)
        return;

      if (pMsg->param1 == 1 && item->HasMusicInfoTag()) // only grab music tag
        SetCurrentSongTag(*item->GetMusicInfoTag());
      else if (pMsg->param1 == 2 && item->HasVideoInfoTag()) // only grab video tag
        SetCurrentVideoTag(*item->GetVideoInfoTag());
      else
        SetCurrentItem(*item);

      delete item;
    }
    break;

    default:
      break;
  }
}

void CGUIInfoManager::RegisterInfoProvider(IGUIInfoProvider* provider)
{
  if (!CServiceBroker::GetWinSystem())
    return;

  std::unique_lock lock(CServiceBroker::GetWinSystem()->GetGfxContext());

  m_infoProviders.RegisterProvider(provider, false);
}

void CGUIInfoManager::UnregisterInfoProvider(IGUIInfoProvider* provider)
{
  if (!CServiceBroker::GetWinSystem())
    return;

  std::unique_lock lock(CServiceBroker::GetWinSystem()->GetGfxContext());

  m_infoProviders.UnregisterProvider(provider);
}
