diff options
Diffstat (limited to 'xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp')
-rw-r--r-- | xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp | 2017 |
1 files changed, 2017 insertions, 0 deletions
diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp new file mode 100644 index 0000000..9cffb9a --- /dev/null +++ b/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp @@ -0,0 +1,2017 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIInfo.h" + +#include "FileItem.h" +#include "GUIInfoManager.h" +#include "ServiceBroker.h" +#include "application/Application.h" +#include "application/ApplicationComponents.h" +#include "application/ApplicationPlayer.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/LocalizeStrings.h" +#include "guilib/guiinfo/GUIInfo.h" +#include "guilib/guiinfo/GUIInfoLabels.h" +#include "pvr/PVRItem.h" +#include "pvr/PVRManager.h" +#include "pvr/PVRPlaybackState.h" +#include "pvr/addons/PVRClient.h" +#include "pvr/addons/PVRClients.h" +#include "pvr/channels/PVRChannel.h" +#include "pvr/channels/PVRChannelGroup.h" +#include "pvr/channels/PVRChannelGroupMember.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/channels/PVRRadioRDSInfoTag.h" +#include "pvr/epg/EpgInfoTag.h" +#include "pvr/epg/EpgSearchFilter.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/providers/PVRProvider.h" +#include "pvr/providers/PVRProviders.h" +#include "pvr/recordings/PVRRecording.h" +#include "pvr/recordings/PVRRecordings.h" +#include "pvr/timers/PVRTimerInfoTag.h" +#include "pvr/timers/PVRTimers.h" +#include "settings/AdvancedSettings.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "threads/SingleLock.h" +#include "threads/SystemClock.h" +#include "utils/StringUtils.h" + +#include <cmath> +#include <ctime> +#include <memory> +#include <mutex> +#include <string> +#include <vector> + +using namespace PVR; +using namespace KODI::GUILIB::GUIINFO; +using namespace std::chrono_literals; + +CPVRGUIInfo::CPVRGUIInfo() : CThread("PVRGUIInfo") +{ + ResetProperties(); +} + +void CPVRGUIInfo::ResetProperties() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + m_anyTimersInfo.ResetProperties(); + m_tvTimersInfo.ResetProperties(); + m_radioTimersInfo.ResetProperties(); + m_timesInfo.Reset(); + m_bHasTVRecordings = false; + m_bHasRadioRecordings = false; + m_iCurrentActiveClient = 0; + m_strPlayingClientName.clear(); + m_strBackendName.clear(); + m_strBackendVersion.clear(); + m_strBackendHost.clear(); + m_strBackendTimers.clear(); + m_strBackendRecordings.clear(); + m_strBackendDeletedRecordings.clear(); + m_strBackendProviders.clear(); + m_strBackendChannelGroups.clear(); + m_strBackendChannels.clear(); + m_iBackendDiskTotal = 0; + m_iBackendDiskUsed = 0; + m_bIsPlayingTV = false; + m_bIsPlayingRadio = false; + m_bIsPlayingRecording = false; + m_bIsPlayingEpgTag = false; + m_bIsPlayingEncryptedStream = false; + m_bIsRecordingPlayingChannel = false; + m_bCanRecordPlayingChannel = false; + m_bIsPlayingActiveRecording = false; + m_bHasTVChannels = false; + m_bHasRadioChannels = false; + + ClearQualityInfo(m_qualityInfo); + ClearDescrambleInfo(m_descrambleInfo); + + m_updateBackendCacheRequested = false; + m_bRegistered = false; +} + +void CPVRGUIInfo::ClearQualityInfo(PVR_SIGNAL_STATUS& qualityInfo) +{ + memset(&qualityInfo, 0, sizeof(qualityInfo)); + strncpy(qualityInfo.strAdapterName, g_localizeStrings.Get(13106).c_str(), + PVR_ADDON_NAME_STRING_LENGTH - 1); + strncpy(qualityInfo.strAdapterStatus, g_localizeStrings.Get(13106).c_str(), + PVR_ADDON_NAME_STRING_LENGTH - 1); +} + +void CPVRGUIInfo::ClearDescrambleInfo(PVR_DESCRAMBLE_INFO& descrambleInfo) +{ + descrambleInfo = {}; +} + +void CPVRGUIInfo::Start() +{ + ResetProperties(); + Create(); + SetPriority(ThreadPriority::BELOW_NORMAL); +} + +void CPVRGUIInfo::Stop() +{ + StopThread(); + + auto& mgr = CServiceBroker::GetPVRManager(); + auto& channels = mgr.Get<PVR::GUI::Channels>(); + channels.GetChannelNavigator().Unsubscribe(this); + channels.Events().Unsubscribe(this); + mgr.Events().Unsubscribe(this); + + CGUIComponent* gui = CServiceBroker::GetGUI(); + if (gui) + { + gui->GetInfoManager().UnregisterInfoProvider(this); + m_bRegistered = false; + } +} + +void CPVRGUIInfo::Notify(const PVREvent& event) +{ + if (event == PVREvent::Timers || event == PVREvent::TimersInvalidated) + UpdateTimersCache(); +} + +void CPVRGUIInfo::Notify(const PVRChannelNumberInputChangedEvent& event) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + m_channelNumberInput = event.m_input; +} + +void CPVRGUIInfo::Notify(const PVRPreviewAndPlayerShowInfoChangedEvent& event) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + m_previewAndPlayerShowInfo = event.m_previewAndPlayerShowInfo; +} + +void CPVRGUIInfo::Process() +{ + auto toggleIntervalMs = std::chrono::milliseconds( + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRInfoToggleInterval); + XbmcThreads::EndTime<> cacheTimer(toggleIntervalMs); + + auto& mgr = CServiceBroker::GetPVRManager(); + mgr.Events().Subscribe(this, &CPVRGUIInfo::Notify); + + auto& channels = mgr.Get<PVR::GUI::Channels>(); + channels.Events().Subscribe(this, &CPVRGUIInfo::Notify); + channels.GetChannelNavigator().Subscribe(this, &CPVRGUIInfo::Notify); + + /* updated on request */ + UpdateTimersCache(); + + /* update the backend cache once initially */ + m_updateBackendCacheRequested = true; + + while (!g_application.m_bStop && !m_bStop) + { + if (!m_bRegistered) + { + CGUIComponent* gui = CServiceBroker::GetGUI(); + if (gui) + { + gui->GetInfoManager().RegisterInfoProvider(this); + m_bRegistered = true; + } + } + + if (!m_bStop) + UpdateQualityData(); + std::this_thread::yield(); + + if (!m_bStop) + UpdateDescrambleData(); + std::this_thread::yield(); + + if (!m_bStop) + UpdateMisc(); + std::this_thread::yield(); + + if (!m_bStop) + UpdateTimeshiftData(); + std::this_thread::yield(); + + if (!m_bStop) + UpdateTimersToggle(); + std::this_thread::yield(); + + if (!m_bStop) + UpdateNextTimer(); + std::this_thread::yield(); + + // Update the backend cache every toggleInterval seconds + if (!m_bStop && cacheTimer.IsTimePast()) + { + UpdateBackendCache(); + cacheTimer.Set(toggleIntervalMs); + } + + if (!m_bStop) + CThread::Sleep(500ms); + } +} + +void CPVRGUIInfo::UpdateQualityData() +{ + if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_PVRPLAYBACK_SIGNALQUALITY)) + return; + + const std::shared_ptr<CPVRPlaybackState> playbackState = + CServiceBroker::GetPVRManager().PlaybackState(); + if (!playbackState) + return; + + PVR_SIGNAL_STATUS qualityInfo; + ClearQualityInfo(qualityInfo); + + const int channelUid = playbackState->GetPlayingChannelUniqueID(); + if (channelUid > 0) + { + const std::shared_ptr<CPVRClient> client = + CServiceBroker::GetPVRManager().Clients()->GetCreatedClient( + playbackState->GetPlayingClientID()); + if (client) + client->SignalQuality(channelUid, qualityInfo); + } + + std::unique_lock<CCriticalSection> lock(m_critSection); + m_qualityInfo = qualityInfo; +} + +void CPVRGUIInfo::UpdateDescrambleData() +{ + const std::shared_ptr<CPVRPlaybackState> playbackState = + CServiceBroker::GetPVRManager().PlaybackState(); + if (!playbackState) + return; + + PVR_DESCRAMBLE_INFO descrambleInfo; + ClearDescrambleInfo(descrambleInfo); + + const int channelUid = playbackState->GetPlayingChannelUniqueID(); + if (channelUid > 0) + { + const std::shared_ptr<CPVRClient> client = + CServiceBroker::GetPVRManager().Clients()->GetCreatedClient( + playbackState->GetPlayingClientID()); + if (client) + client->GetDescrambleInfo(channelUid, descrambleInfo); + } + + std::unique_lock<CCriticalSection> lock(m_critSection); + m_descrambleInfo = descrambleInfo; +} + +void CPVRGUIInfo::UpdateMisc() +{ + const CPVRManager& mgr = CServiceBroker::GetPVRManager(); + bool bStarted = mgr.IsStarted(); + const std::shared_ptr<CPVRPlaybackState> state = mgr.PlaybackState(); + + /* safe to fetch these unlocked, since they're updated from the same thread as this one */ + const std::string strPlayingClientName = bStarted ? state->GetPlayingClientName() : ""; + const bool bHasTVRecordings = bStarted && mgr.Recordings()->GetNumTVRecordings() > 0; + const bool bHasRadioRecordings = bStarted && mgr.Recordings()->GetNumRadioRecordings() > 0; + const bool bIsPlayingTV = bStarted && state->IsPlayingTV(); + const bool bIsPlayingRadio = bStarted && state->IsPlayingRadio(); + const bool bIsPlayingRecording = bStarted && state->IsPlayingRecording(); + const bool bIsPlayingEpgTag = bStarted && state->IsPlayingEpgTag(); + const bool bIsPlayingEncryptedStream = bStarted && state->IsPlayingEncryptedChannel(); + const bool bHasTVChannels = bStarted && mgr.ChannelGroups()->GetGroupAllTV()->HasChannels(); + const bool bHasRadioChannels = bStarted && mgr.ChannelGroups()->GetGroupAllRadio()->HasChannels(); + const bool bCanRecordPlayingChannel = bStarted && state->CanRecordOnPlayingChannel(); + const bool bIsRecordingPlayingChannel = bStarted && state->IsRecordingOnPlayingChannel(); + const bool bIsPlayingActiveRecording = bStarted && state->IsPlayingActiveRecording(); + const std::string strPlayingTVGroup = + (bStarted && bIsPlayingTV) ? state->GetActiveChannelGroup(false)->GroupName() : ""; + const std::string strPlayingRadioGroup = + (bStarted && bIsPlayingRadio) ? state->GetActiveChannelGroup(true)->GroupName() : ""; + + std::unique_lock<CCriticalSection> lock(m_critSection); + m_strPlayingClientName = strPlayingClientName; + m_bHasTVRecordings = bHasTVRecordings; + m_bHasRadioRecordings = bHasRadioRecordings; + m_bIsPlayingTV = bIsPlayingTV; + m_bIsPlayingRadio = bIsPlayingRadio; + m_bIsPlayingRecording = bIsPlayingRecording; + m_bIsPlayingEpgTag = bIsPlayingEpgTag; + m_bIsPlayingEncryptedStream = bIsPlayingEncryptedStream; + m_bHasTVChannels = bHasTVChannels; + m_bHasRadioChannels = bHasRadioChannels; + m_strPlayingTVGroup = strPlayingTVGroup; + m_strPlayingRadioGroup = strPlayingRadioGroup; + m_bCanRecordPlayingChannel = bCanRecordPlayingChannel; + m_bIsRecordingPlayingChannel = bIsRecordingPlayingChannel; + m_bIsPlayingActiveRecording = bIsPlayingActiveRecording; +} + +void CPVRGUIInfo::UpdateTimeshiftData() +{ + m_timesInfo.Update(); +} + +bool CPVRGUIInfo::InitCurrentItem(CFileItem* item) +{ + CServiceBroker::GetPVRManager().PublishEvent(PVREvent::CurrentItem); + return false; +} + +bool CPVRGUIInfo::GetLabel(std::string& value, + const CFileItem* item, + int contextWindow, + const CGUIInfo& info, + std::string* fallback) const +{ + return GetListItemAndPlayerLabel(item, info, value) || GetPVRLabel(item, info, value) || + GetRadioRDSLabel(item, info, value); +} + +namespace +{ +std::string GetAsLocalizedDateString(const CDateTime& datetime, bool bLongDate) +{ + return datetime.IsValid() ? datetime.GetAsLocalizedDate(bLongDate) : ""; +} + +std::string GetAsLocalizedTimeString(const CDateTime& datetime) +{ + return datetime.IsValid() ? datetime.GetAsLocalizedTime("", false) : ""; +} + +std::string GetAsLocalizedDateTimeString(const CDateTime& datetime) +{ + return datetime.IsValid() ? datetime.GetAsLocalizedDateTime(false, false) : ""; +} + +std::string GetEpgTagTitle(const std::shared_ptr<CPVREpgInfoTag>& epgTag) +{ + if (epgTag) + { + if (CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) + return g_localizeStrings.Get(19266); // Parental locked + else if (!epgTag->Title().empty()) + return epgTag->Title(); + } + + if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_EPG_HIDENOINFOAVAILABLE)) + return g_localizeStrings.Get(19055); // no information available + + return {}; +} + +} // unnamed namespace + +bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem* item, + const CGUIInfo& info, + std::string& strValue) const +{ + const std::shared_ptr<CPVRTimerInfoTag> timer = item->GetPVRTimerInfoTag(); + if (timer) + { + switch (info.m_info) + { + case LISTITEM_DATE: + strValue = timer->Summary(); + return true; + case LISTITEM_STARTDATE: + strValue = GetAsLocalizedDateString(timer->StartAsLocalTime(), true); + return true; + case LISTITEM_STARTTIME: + strValue = GetAsLocalizedTimeString(timer->StartAsLocalTime()); + return true; + case LISTITEM_ENDDATE: + strValue = GetAsLocalizedDateString(timer->EndAsLocalTime(), true); + return true; + case LISTITEM_ENDTIME: + strValue = GetAsLocalizedTimeString(timer->EndAsLocalTime()); + return true; + case LISTITEM_DURATION: + if (timer->GetDuration() > 0) + { + strValue = StringUtils::SecondsToTimeString(timer->GetDuration(), + static_cast<TIME_FORMAT>(info.GetData4())); + return true; + } + return false; + case LISTITEM_TITLE: + strValue = timer->Title(); + return true; + case LISTITEM_COMMENT: + strValue = + timer->GetStatus(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == + WINDOW_RADIO_TIMER_RULES); + return true; + case LISTITEM_TIMERTYPE: + strValue = timer->GetTypeAsString(); + return true; + case LISTITEM_CHANNEL_NAME: + strValue = timer->ChannelName(); + return true; + case LISTITEM_EPG_EVENT_TITLE: + case LISTITEM_EPG_EVENT_ICON: + case LISTITEM_GENRE: + case LISTITEM_PLOT: + case LISTITEM_PLOT_OUTLINE: + case LISTITEM_ORIGINALTITLE: + case LISTITEM_YEAR: + case LISTITEM_SEASON: + case LISTITEM_EPISODE: + case LISTITEM_EPISODENAME: + case LISTITEM_DIRECTOR: + case LISTITEM_CHANNEL_NUMBER: + case LISTITEM_PREMIERED: + break; // obtain value from channel/epg + default: + return false; + } + } + + const std::shared_ptr<CPVRRecording> recording(item->GetPVRRecordingInfoTag()); + if (recording) + { + // Note: CPVRRecoding is derived from CVideoInfoTag. All base class properties will be handled + // by CVideoGUIInfoProvider. Only properties introduced by CPVRRecording need to be handled here. + switch (info.m_info) + { + case LISTITEM_DATE: + strValue = GetAsLocalizedDateTimeString(recording->RecordingTimeAsLocalTime()); + return true; + case LISTITEM_STARTDATE: + strValue = GetAsLocalizedDateString(recording->RecordingTimeAsLocalTime(), true); + return true; + case VIDEOPLAYER_STARTTIME: + case LISTITEM_STARTTIME: + strValue = GetAsLocalizedTimeString(recording->RecordingTimeAsLocalTime()); + return true; + case LISTITEM_ENDDATE: + strValue = GetAsLocalizedDateString(recording->EndTimeAsLocalTime(), true); + return true; + case VIDEOPLAYER_ENDTIME: + case LISTITEM_ENDTIME: + strValue = GetAsLocalizedTimeString(recording->EndTimeAsLocalTime()); + return true; + case LISTITEM_EXPIRATION_DATE: + if (recording->HasExpirationTime()) + { + strValue = GetAsLocalizedDateString(recording->ExpirationTimeAsLocalTime(), false); + return true; + } + break; + case LISTITEM_EXPIRATION_TIME: + if (recording->HasExpirationTime()) + { + strValue = GetAsLocalizedTimeString(recording->ExpirationTimeAsLocalTime()); + ; + return true; + } + break; + case VIDEOPLAYER_EPISODENAME: + case LISTITEM_EPISODENAME: + strValue = recording->EpisodeName(); + // fixup multiline episode name strings (which do not fit in any way in our GUI) + StringUtils::Replace(strValue, "\n", ", "); + return true; + case VIDEOPLAYER_CHANNEL_NAME: + case LISTITEM_CHANNEL_NAME: + strValue = recording->ChannelName(); + if (strValue.empty()) + { + if (recording->ProviderName().empty()) + { + const auto& provider = recording->GetProvider(); + strValue = provider->GetName(); + } + else + { + strValue = recording->ProviderName(); + } + } + return true; + case VIDEOPLAYER_CHANNEL_NUMBER: + case LISTITEM_CHANNEL_NUMBER: + { + const std::shared_ptr<CPVRChannelGroupMember> groupMember = + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(*item); + if (groupMember) + { + strValue = groupMember->ChannelNumber().FormattedChannelNumber(); + return true; + } + break; + } + case LISTITEM_ICON: + if (recording->ClientIconPath().empty() && recording->ClientThumbnailPath().empty() && + // Only use a fallback if there is more than a single provider available + // Note: an add-on itself is a provider, hence we don't use > 0 + CServiceBroker::GetPVRManager().Providers()->GetNumProviders() > 1 && + !recording->Channel()) + { + auto provider = recording->GetProvider(); + if (!provider->GetIconPath().empty()) + { + strValue = provider->GetIconPath(); + return true; + } + } + return false; + case VIDEOPLAYER_CHANNEL_GROUP: + { + std::unique_lock<CCriticalSection> lock(m_critSection); + strValue = recording->IsRadio() ? m_strPlayingRadioGroup : m_strPlayingTVGroup; + return true; + } + case VIDEOPLAYER_PREMIERED: + case LISTITEM_PREMIERED: + if (recording->FirstAired().IsValid()) + { + strValue = recording->FirstAired().GetAsLocalizedDate(); + return true; + } + else if (recording->HasYear()) + { + strValue = std::to_string(recording->GetYear()); + return true; + } + return false; + case LISTITEM_SIZE: + if (recording->GetSizeInBytes() > 0) + { + strValue = StringUtils::SizeToString(recording->GetSizeInBytes()); + return true; + } + return false; + } + return false; + } + + const std::shared_ptr<CPVREpgSearchFilter> filter = item->GetEPGSearchFilter(); + if (filter) + { + switch (info.m_info) + { + case LISTITEM_DATE: + { + CDateTime lastExecLocal; + lastExecLocal.SetFromUTCDateTime(filter->GetLastExecutedDateTime()); + strValue = GetAsLocalizedDateTimeString(lastExecLocal); + if (strValue.empty()) + strValue = g_localizeStrings.Get(10006); // "N/A" + return true; + } + } + return false; + } + + std::shared_ptr<CPVREpgInfoTag> epgTag; + std::shared_ptr<CPVRChannel> channel; + if (item->IsPVRChannel() || item->IsEPG() || item->IsPVRTimer()) + { + CPVRItem pvrItem(item); + channel = pvrItem.GetChannel(); + + switch (info.m_info) + { + case VIDEOPLAYER_NEXT_TITLE: + case VIDEOPLAYER_NEXT_GENRE: + case VIDEOPLAYER_NEXT_PLOT: + case VIDEOPLAYER_NEXT_PLOT_OUTLINE: + case VIDEOPLAYER_NEXT_STARTTIME: + case VIDEOPLAYER_NEXT_ENDTIME: + case VIDEOPLAYER_NEXT_DURATION: + case LISTITEM_NEXT_TITLE: + case LISTITEM_NEXT_GENRE: + case LISTITEM_NEXT_PLOT: + case LISTITEM_NEXT_PLOT_OUTLINE: + case LISTITEM_NEXT_STARTDATE: + case LISTITEM_NEXT_STARTTIME: + case LISTITEM_NEXT_ENDDATE: + case LISTITEM_NEXT_ENDTIME: + case LISTITEM_NEXT_DURATION: + // next playing event + epgTag = pvrItem.GetNextEpgInfoTag(); + break; + default: + // now playing event + epgTag = pvrItem.GetEpgInfoTag(); + break; + } + + switch (info.m_info) + { + // special handling for channels without epg or with radio rds data + case PLAYER_TITLE: + case LISTITEM_TITLE: + case VIDEOPLAYER_NEXT_TITLE: + case LISTITEM_NEXT_TITLE: + case LISTITEM_EPG_EVENT_TITLE: + // Note: in difference to LISTITEM_TITLE, LISTITEM_EPG_EVENT_TITLE returns the title + // associated with the epg event of a timer, if any, and not the title of the timer. + strValue = GetEpgTagTitle(epgTag); + return true; + } + } + + if (epgTag) + { + switch (info.m_info) + { + case VIDEOPLAYER_GENRE: + case LISTITEM_GENRE: + case VIDEOPLAYER_NEXT_GENRE: + case LISTITEM_NEXT_GENRE: + strValue = epgTag->GetGenresLabel(); + return true; + case VIDEOPLAYER_PLOT: + case LISTITEM_PLOT: + case VIDEOPLAYER_NEXT_PLOT: + case LISTITEM_NEXT_PLOT: + if (!CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) + strValue = epgTag->Plot(); + return true; + case VIDEOPLAYER_PLOT_OUTLINE: + case LISTITEM_PLOT_OUTLINE: + case VIDEOPLAYER_NEXT_PLOT_OUTLINE: + case LISTITEM_NEXT_PLOT_OUTLINE: + if (!CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) + strValue = epgTag->PlotOutline(); + return true; + case LISTITEM_DATE: + strValue = GetAsLocalizedDateTimeString(epgTag->StartAsLocalTime()); + return true; + case LISTITEM_STARTDATE: + case LISTITEM_NEXT_STARTDATE: + strValue = GetAsLocalizedDateString(epgTag->StartAsLocalTime(), true); + return true; + case VIDEOPLAYER_STARTTIME: + case VIDEOPLAYER_NEXT_STARTTIME: + case LISTITEM_STARTTIME: + case LISTITEM_NEXT_STARTTIME: + strValue = GetAsLocalizedTimeString(epgTag->StartAsLocalTime()); + return true; + case LISTITEM_ENDDATE: + case LISTITEM_NEXT_ENDDATE: + strValue = GetAsLocalizedDateString(epgTag->EndAsLocalTime(), true); + return true; + case VIDEOPLAYER_ENDTIME: + case VIDEOPLAYER_NEXT_ENDTIME: + case LISTITEM_ENDTIME: + case LISTITEM_NEXT_ENDTIME: + strValue = GetAsLocalizedTimeString(epgTag->EndAsLocalTime()); + return true; + // note: for some reason, there is no VIDEOPLAYER_DURATION + case LISTITEM_DURATION: + case VIDEOPLAYER_NEXT_DURATION: + case LISTITEM_NEXT_DURATION: + if (epgTag->GetDuration() > 0) + { + strValue = StringUtils::SecondsToTimeString(epgTag->GetDuration(), + static_cast<TIME_FORMAT>(info.GetData4())); + return true; + } + return false; + case VIDEOPLAYER_IMDBNUMBER: + case LISTITEM_IMDBNUMBER: + strValue = epgTag->IMDBNumber(); + return true; + case VIDEOPLAYER_ORIGINALTITLE: + case LISTITEM_ORIGINALTITLE: + if (!CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) + strValue = epgTag->OriginalTitle(); + return true; + case VIDEOPLAYER_YEAR: + case LISTITEM_YEAR: + if (epgTag->Year() > 0) + { + strValue = std::to_string(epgTag->Year()); + return true; + } + return false; + case VIDEOPLAYER_SEASON: + case LISTITEM_SEASON: + if (epgTag->SeriesNumber() >= 0) + { + strValue = std::to_string(epgTag->SeriesNumber()); + return true; + } + return false; + case VIDEOPLAYER_EPISODE: + case LISTITEM_EPISODE: + if (epgTag->EpisodeNumber() >= 0) + { + strValue = std::to_string(epgTag->EpisodeNumber()); + return true; + } + return false; + case VIDEOPLAYER_EPISODENAME: + case LISTITEM_EPISODENAME: + if (!CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) + { + strValue = epgTag->EpisodeName(); + // fixup multiline episode name strings (which do not fit in any way in our GUI) + StringUtils::Replace(strValue, "\n", ", "); + } + return true; + case VIDEOPLAYER_CAST: + case LISTITEM_CAST: + strValue = epgTag->GetCastLabel(); + return true; + case VIDEOPLAYER_DIRECTOR: + case LISTITEM_DIRECTOR: + strValue = epgTag->GetDirectorsLabel(); + return true; + case VIDEOPLAYER_WRITER: + case LISTITEM_WRITER: + strValue = epgTag->GetWritersLabel(); + return true; + case LISTITEM_EPG_EVENT_ICON: + strValue = epgTag->IconPath(); + return true; + case VIDEOPLAYER_PARENTAL_RATING: + case LISTITEM_PARENTAL_RATING: + if (epgTag->ParentalRating() > 0) + { + strValue = std::to_string(epgTag->ParentalRating()); + return true; + } + return false; + case VIDEOPLAYER_PREMIERED: + case LISTITEM_PREMIERED: + if (epgTag->FirstAired().IsValid()) + { + strValue = epgTag->FirstAired().GetAsLocalizedDate(); + return true; + } + else if (epgTag->Year() > 0) + { + strValue = std::to_string(epgTag->Year()); + return true; + } + return false; + case VIDEOPLAYER_RATING: + case LISTITEM_RATING: + { + int iStarRating = epgTag->StarRating(); + if (iStarRating > 0) + { + strValue = StringUtils::FormatNumber(iStarRating); + return true; + } + return false; + } + } + } + + if (channel) + { + switch (info.m_info) + { + case MUSICPLAYER_CHANNEL_NAME: + { + const std::shared_ptr<CPVRRadioRDSInfoTag> rdsTag = channel->GetRadioRDSInfoTag(); + if (rdsTag) + { + strValue = rdsTag->GetProgStation(); + if (!strValue.empty()) + return true; + } + // fall-thru is intended + [[fallthrough]]; + } + case VIDEOPLAYER_CHANNEL_NAME: + case LISTITEM_CHANNEL_NAME: + strValue = channel->ChannelName(); + return true; + case MUSICPLAYER_CHANNEL_NUMBER: + case VIDEOPLAYER_CHANNEL_NUMBER: + case LISTITEM_CHANNEL_NUMBER: + { + auto groupMember = item->GetPVRChannelGroupMemberInfoTag(); + if (!groupMember) + groupMember = + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember( + *item); + if (groupMember) + { + strValue = groupMember->ChannelNumber().FormattedChannelNumber(); + return true; + } + break; + } + case MUSICPLAYER_CHANNEL_GROUP: + case VIDEOPLAYER_CHANNEL_GROUP: + { + std::unique_lock<CCriticalSection> lock(m_critSection); + strValue = channel->IsRadio() ? m_strPlayingRadioGroup : m_strPlayingTVGroup; + return true; + } + } + } + + return false; +} + +bool CPVRGUIInfo::GetPVRLabel(const CFileItem* item, + const CGUIInfo& info, + std::string& strValue) const +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + switch (info.m_info) + { + case PVR_EPG_EVENT_ICON: + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = + (item->IsPVRChannel() || item->IsEPG()) ? CPVRItem(item).GetEpgInfoTag() : nullptr; + if (epgTag) + { + strValue = epgTag->IconPath(); + } + return true; + } + case PVR_EPG_EVENT_DURATION: + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = + (item->IsPVRChannel() || item->IsEPG()) ? CPVRItem(item).GetEpgInfoTag() : nullptr; + strValue = m_timesInfo.GetEpgEventDuration(epgTag, static_cast<TIME_FORMAT>(info.GetData1())); + return true; + } + case PVR_EPG_EVENT_ELAPSED_TIME: + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = + (item->IsPVRChannel() || item->IsEPG()) ? CPVRItem(item).GetEpgInfoTag() : nullptr; + strValue = + m_timesInfo.GetEpgEventElapsedTime(epgTag, static_cast<TIME_FORMAT>(info.GetData1())); + return true; + } + case PVR_EPG_EVENT_REMAINING_TIME: + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = + (item->IsPVRChannel() || item->IsEPG()) ? CPVRItem(item).GetEpgInfoTag() : nullptr; + strValue = + m_timesInfo.GetEpgEventRemainingTime(epgTag, static_cast<TIME_FORMAT>(info.GetData1())); + return true; + } + case PVR_EPG_EVENT_FINISH_TIME: + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = + (item->IsPVRChannel() || item->IsEPG()) ? CPVRItem(item).GetEpgInfoTag() : nullptr; + strValue = + m_timesInfo.GetEpgEventFinishTime(epgTag, static_cast<TIME_FORMAT>(info.GetData1())); + return true; + } + case PVR_TIMESHIFT_START_TIME: + strValue = m_timesInfo.GetTimeshiftStartTime(static_cast<TIME_FORMAT>(info.GetData1())); + return true; + case PVR_TIMESHIFT_END_TIME: + strValue = m_timesInfo.GetTimeshiftEndTime(static_cast<TIME_FORMAT>(info.GetData1())); + return true; + case PVR_TIMESHIFT_PLAY_TIME: + strValue = m_timesInfo.GetTimeshiftPlayTime(static_cast<TIME_FORMAT>(info.GetData1())); + return true; + case PVR_TIMESHIFT_OFFSET: + strValue = m_timesInfo.GetTimeshiftOffset(static_cast<TIME_FORMAT>(info.GetData1())); + return true; + case PVR_TIMESHIFT_PROGRESS_DURATION: + strValue = + m_timesInfo.GetTimeshiftProgressDuration(static_cast<TIME_FORMAT>(info.GetData1())); + return true; + case PVR_TIMESHIFT_PROGRESS_START_TIME: + strValue = + m_timesInfo.GetTimeshiftProgressStartTime(static_cast<TIME_FORMAT>(info.GetData1())); + return true; + case PVR_TIMESHIFT_PROGRESS_END_TIME: + strValue = m_timesInfo.GetTimeshiftProgressEndTime(static_cast<TIME_FORMAT>(info.GetData1())); + return true; + case PVR_EPG_EVENT_SEEK_TIME: + { + const auto& components = CServiceBroker::GetAppComponents(); + const auto appPlayer = components.GetComponent<CApplicationPlayer>(); + strValue = m_timesInfo.GetEpgEventSeekTime(appPlayer->GetSeekHandler().GetSeekSize(), + static_cast<TIME_FORMAT>(info.GetData1())); + return true; + } + case PVR_NOW_RECORDING_TITLE: + strValue = m_anyTimersInfo.GetActiveTimerTitle(); + return true; + case PVR_NOW_RECORDING_CHANNEL: + strValue = m_anyTimersInfo.GetActiveTimerChannelName(); + return true; + case PVR_NOW_RECORDING_CHAN_ICO: + strValue = m_anyTimersInfo.GetActiveTimerChannelIcon(); + return true; + case PVR_NOW_RECORDING_DATETIME: + strValue = m_anyTimersInfo.GetActiveTimerDateTime(); + return true; + case PVR_NEXT_RECORDING_TITLE: + strValue = m_anyTimersInfo.GetNextTimerTitle(); + return true; + case PVR_NEXT_RECORDING_CHANNEL: + strValue = m_anyTimersInfo.GetNextTimerChannelName(); + return true; + case PVR_NEXT_RECORDING_CHAN_ICO: + strValue = m_anyTimersInfo.GetNextTimerChannelIcon(); + return true; + case PVR_NEXT_RECORDING_DATETIME: + strValue = m_anyTimersInfo.GetNextTimerDateTime(); + return true; + case PVR_TV_NOW_RECORDING_TITLE: + strValue = m_tvTimersInfo.GetActiveTimerTitle(); + return true; + case PVR_TV_NOW_RECORDING_CHANNEL: + strValue = m_tvTimersInfo.GetActiveTimerChannelName(); + return true; + case PVR_TV_NOW_RECORDING_CHAN_ICO: + strValue = m_tvTimersInfo.GetActiveTimerChannelIcon(); + return true; + case PVR_TV_NOW_RECORDING_DATETIME: + strValue = m_tvTimersInfo.GetActiveTimerDateTime(); + return true; + case PVR_TV_NEXT_RECORDING_TITLE: + strValue = m_tvTimersInfo.GetNextTimerTitle(); + return true; + case PVR_TV_NEXT_RECORDING_CHANNEL: + strValue = m_tvTimersInfo.GetNextTimerChannelName(); + return true; + case PVR_TV_NEXT_RECORDING_CHAN_ICO: + strValue = m_tvTimersInfo.GetNextTimerChannelIcon(); + return true; + case PVR_TV_NEXT_RECORDING_DATETIME: + strValue = m_tvTimersInfo.GetNextTimerDateTime(); + return true; + case PVR_RADIO_NOW_RECORDING_TITLE: + strValue = m_radioTimersInfo.GetActiveTimerTitle(); + return true; + case PVR_RADIO_NOW_RECORDING_CHANNEL: + strValue = m_radioTimersInfo.GetActiveTimerChannelName(); + return true; + case PVR_RADIO_NOW_RECORDING_CHAN_ICO: + strValue = m_radioTimersInfo.GetActiveTimerChannelIcon(); + return true; + case PVR_RADIO_NOW_RECORDING_DATETIME: + strValue = m_radioTimersInfo.GetActiveTimerDateTime(); + return true; + case PVR_RADIO_NEXT_RECORDING_TITLE: + strValue = m_radioTimersInfo.GetNextTimerTitle(); + return true; + case PVR_RADIO_NEXT_RECORDING_CHANNEL: + strValue = m_radioTimersInfo.GetNextTimerChannelName(); + return true; + case PVR_RADIO_NEXT_RECORDING_CHAN_ICO: + strValue = m_radioTimersInfo.GetNextTimerChannelIcon(); + return true; + case PVR_RADIO_NEXT_RECORDING_DATETIME: + strValue = m_radioTimersInfo.GetNextTimerDateTime(); + return true; + case PVR_NEXT_TIMER: + strValue = m_anyTimersInfo.GetNextTimer(); + return true; + case PVR_ACTUAL_STREAM_SIG: + CharInfoSignal(strValue); + return true; + case PVR_ACTUAL_STREAM_SNR: + CharInfoSNR(strValue); + return true; + case PVR_ACTUAL_STREAM_BER: + CharInfoBER(strValue); + return true; + case PVR_ACTUAL_STREAM_UNC: + CharInfoUNC(strValue); + return true; + case PVR_ACTUAL_STREAM_CLIENT: + CharInfoPlayingClientName(strValue); + return true; + case PVR_ACTUAL_STREAM_DEVICE: + CharInfoFrontendName(strValue); + return true; + case PVR_ACTUAL_STREAM_STATUS: + CharInfoFrontendStatus(strValue); + return true; + case PVR_ACTUAL_STREAM_CRYPTION: + CharInfoEncryption(strValue); + return true; + case PVR_ACTUAL_STREAM_SERVICE: + CharInfoService(strValue); + return true; + case PVR_ACTUAL_STREAM_MUX: + CharInfoMux(strValue); + return true; + case PVR_ACTUAL_STREAM_PROVIDER: + CharInfoProvider(strValue); + return true; + case PVR_BACKEND_NAME: + CharInfoBackendName(strValue); + return true; + case PVR_BACKEND_VERSION: + CharInfoBackendVersion(strValue); + return true; + case PVR_BACKEND_HOST: + CharInfoBackendHost(strValue); + return true; + case PVR_BACKEND_DISKSPACE: + CharInfoBackendDiskspace(strValue); + return true; + case PVR_BACKEND_PROVIDERS: + CharInfoBackendProviders(strValue); + return true; + case PVR_BACKEND_CHANNEL_GROUPS: + CharInfoBackendChannelGroups(strValue); + return true; + case PVR_BACKEND_CHANNELS: + CharInfoBackendChannels(strValue); + return true; + case PVR_BACKEND_TIMERS: + CharInfoBackendTimers(strValue); + return true; + case PVR_BACKEND_RECORDINGS: + CharInfoBackendRecordings(strValue); + return true; + case PVR_BACKEND_DELETED_RECORDINGS: + CharInfoBackendDeletedRecordings(strValue); + return true; + case PVR_BACKEND_NUMBER: + CharInfoBackendNumber(strValue); + return true; + case PVR_TOTAL_DISKSPACE: + CharInfoTotalDiskSpace(strValue); + return true; + case PVR_CHANNEL_NUMBER_INPUT: + strValue = m_channelNumberInput; + return true; + } + + return false; +} + +bool CPVRGUIInfo::GetRadioRDSLabel(const CFileItem* item, + const CGUIInfo& info, + std::string& strValue) const +{ + if (!item->HasPVRChannelInfoTag()) + return false; + + const std::shared_ptr<CPVRRadioRDSInfoTag> tag = + item->GetPVRChannelInfoTag()->GetRadioRDSInfoTag(); + if (tag) + { + switch (info.m_info) + { + case RDS_CHANNEL_COUNTRY: + strValue = tag->GetCountry(); + return true; + case RDS_TITLE: + strValue = tag->GetTitle(); + return true; + case RDS_ARTIST: + strValue = tag->GetArtist(); + return true; + case RDS_BAND: + strValue = tag->GetBand(); + return true; + case RDS_COMPOSER: + strValue = tag->GetComposer(); + return true; + case RDS_CONDUCTOR: + strValue = tag->GetConductor(); + return true; + case RDS_ALBUM: + strValue = tag->GetAlbum(); + return true; + case RDS_ALBUM_TRACKNUMBER: + if (tag->GetAlbumTrackNumber() > 0) + { + strValue = std::to_string(tag->GetAlbumTrackNumber()); + return true; + } + break; + case RDS_GET_RADIO_STYLE: + strValue = tag->GetRadioStyle(); + return true; + case RDS_COMMENT: + strValue = tag->GetComment(); + return true; + case RDS_INFO_NEWS: + strValue = tag->GetInfoNews(); + return true; + case RDS_INFO_NEWS_LOCAL: + strValue = tag->GetInfoNewsLocal(); + return true; + case RDS_INFO_STOCK: + strValue = tag->GetInfoStock(); + return true; + case RDS_INFO_STOCK_SIZE: + strValue = std::to_string(static_cast<int>(tag->GetInfoStock().size())); + return true; + case RDS_INFO_SPORT: + strValue = tag->GetInfoSport(); + return true; + case RDS_INFO_SPORT_SIZE: + strValue = std::to_string(static_cast<int>(tag->GetInfoSport().size())); + return true; + case RDS_INFO_LOTTERY: + strValue = tag->GetInfoLottery(); + return true; + case RDS_INFO_LOTTERY_SIZE: + strValue = std::to_string(static_cast<int>(tag->GetInfoLottery().size())); + return true; + case RDS_INFO_WEATHER: + strValue = tag->GetInfoWeather(); + return true; + case RDS_INFO_WEATHER_SIZE: + strValue = std::to_string(static_cast<int>(tag->GetInfoWeather().size())); + return true; + case RDS_INFO_HOROSCOPE: + strValue = tag->GetInfoHoroscope(); + return true; + case RDS_INFO_HOROSCOPE_SIZE: + strValue = std::to_string(static_cast<int>(tag->GetInfoHoroscope().size())); + return true; + case RDS_INFO_CINEMA: + strValue = tag->GetInfoCinema(); + return true; + case RDS_INFO_CINEMA_SIZE: + strValue = std::to_string(static_cast<int>(tag->GetInfoCinema().size())); + return true; + case RDS_INFO_OTHER: + strValue = tag->GetInfoOther(); + return true; + case RDS_INFO_OTHER_SIZE: + strValue = std::to_string(static_cast<int>(tag->GetInfoOther().size())); + return true; + case RDS_PROG_HOST: + strValue = tag->GetProgHost(); + return true; + case RDS_PROG_EDIT_STAFF: + strValue = tag->GetEditorialStaff(); + return true; + case RDS_PROG_HOMEPAGE: + strValue = tag->GetProgWebsite(); + return true; + case RDS_PROG_STYLE: + strValue = tag->GetProgStyle(); + return true; + case RDS_PHONE_HOTLINE: + strValue = tag->GetPhoneHotline(); + return true; + case RDS_PHONE_STUDIO: + strValue = tag->GetPhoneStudio(); + return true; + case RDS_SMS_STUDIO: + strValue = tag->GetSMSStudio(); + return true; + case RDS_EMAIL_HOTLINE: + strValue = tag->GetEMailHotline(); + return true; + case RDS_EMAIL_STUDIO: + strValue = tag->GetEMailStudio(); + return true; + case RDS_PROG_STATION: + strValue = tag->GetProgStation(); + return true; + case RDS_PROG_NOW: + strValue = tag->GetProgNow(); + return true; + case RDS_PROG_NEXT: + strValue = tag->GetProgNext(); + return true; + case RDS_AUDIO_LANG: + strValue = tag->GetLanguage(); + return true; + case RDS_GET_RADIOTEXT_LINE: + strValue = tag->GetRadioText(info.GetData1()); + return true; + } + } + return false; +} + +bool CPVRGUIInfo::GetFallbackLabel(std::string& value, + const CFileItem* item, + int contextWindow, + const CGUIInfo& info, + std::string* fallback) +{ + if (item->IsPVRChannel() || item->IsEPG() || item->IsPVRTimer()) + { + switch (info.m_info) + { + ///////////////////////////////////////////////////////////////////////////////////////////// + // VIDEOPLAYER_*, MUSICPLAYER_* + ///////////////////////////////////////////////////////////////////////////////////////////// + case VIDEOPLAYER_TITLE: + case MUSICPLAYER_TITLE: + value = GetEpgTagTitle(CPVRItem(item).GetEpgInfoTag()); + return !value.empty(); + default: + break; + } + } + return false; +} + +bool CPVRGUIInfo::GetInt(int& value, + const CGUIListItem* item, + int contextWindow, + const CGUIInfo& info) const +{ + if (!item->IsFileItem()) + return false; + + const CFileItem* fitem = static_cast<const CFileItem*>(item); + return GetListItemAndPlayerInt(fitem, info, value) || GetPVRInt(fitem, info, value); +} + +bool CPVRGUIInfo::GetListItemAndPlayerInt(const CFileItem* item, + const CGUIInfo& info, + int& iValue) const +{ + switch (info.m_info) + { + case LISTITEM_PROGRESS: + if (item->IsPVRChannel() || item->IsEPG()) + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = CPVRItem(item).GetEpgInfoTag(); + if (epgTag) + iValue = static_cast<int>(epgTag->ProgressPercentage()); + } + return true; + } + return false; +} + +bool CPVRGUIInfo::GetPVRInt(const CFileItem* item, const CGUIInfo& info, int& iValue) const +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + switch (info.m_info) + { + case PVR_EPG_EVENT_DURATION: + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = + (item->IsPVRChannel() || item->IsEPG()) ? CPVRItem(item).GetEpgInfoTag() : nullptr; + iValue = m_timesInfo.GetEpgEventDuration(epgTag); + return true; + } + case PVR_EPG_EVENT_PROGRESS: + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = + (item->IsPVRChannel() || item->IsEPG()) ? CPVRItem(item).GetEpgInfoTag() : nullptr; + iValue = m_timesInfo.GetEpgEventProgress(epgTag); + return true; + } + case PVR_TIMESHIFT_PROGRESS: + iValue = m_timesInfo.GetTimeshiftProgress(); + return true; + case PVR_TIMESHIFT_PROGRESS_DURATION: + iValue = m_timesInfo.GetTimeshiftProgressDuration(); + return true; + case PVR_TIMESHIFT_PROGRESS_PLAY_POS: + iValue = m_timesInfo.GetTimeshiftProgressPlayPosition(); + return true; + case PVR_TIMESHIFT_PROGRESS_EPG_START: + iValue = m_timesInfo.GetTimeshiftProgressEpgStart(); + return true; + case PVR_TIMESHIFT_PROGRESS_EPG_END: + iValue = m_timesInfo.GetTimeshiftProgressEpgEnd(); + return true; + case PVR_TIMESHIFT_PROGRESS_BUFFER_START: + iValue = m_timesInfo.GetTimeshiftProgressBufferStart(); + return true; + case PVR_TIMESHIFT_PROGRESS_BUFFER_END: + iValue = m_timesInfo.GetTimeshiftProgressBufferEnd(); + return true; + case PVR_TIMESHIFT_SEEKBAR: + iValue = GetTimeShiftSeekPercent(); + return true; + case PVR_ACTUAL_STREAM_SIG_PROGR: + iValue = std::lrintf(static_cast<float>(m_qualityInfo.iSignal) / 0xFFFF * 100); + return true; + case PVR_ACTUAL_STREAM_SNR_PROGR: + iValue = std::lrintf(static_cast<float>(m_qualityInfo.iSNR) / 0xFFFF * 100); + return true; + case PVR_BACKEND_DISKSPACE_PROGR: + if (m_iBackendDiskTotal > 0) + iValue = std::lrintf(static_cast<float>(m_iBackendDiskUsed) / m_iBackendDiskTotal * 100); + else + iValue = 0xFF; + return true; + } + return false; +} + +bool CPVRGUIInfo::GetBool(bool& value, + const CGUIListItem* item, + int contextWindow, + const CGUIInfo& info) const +{ + if (!item->IsFileItem()) + return false; + + const CFileItem* fitem = static_cast<const CFileItem*>(item); + return GetListItemAndPlayerBool(fitem, info, value) || GetPVRBool(fitem, info, value) || + GetRadioRDSBool(fitem, info, value); +} + +bool CPVRGUIInfo::GetListItemAndPlayerBool(const CFileItem* item, + const CGUIInfo& info, + bool& bValue) const +{ + switch (info.m_info) + { + case LISTITEM_HASARCHIVE: + if (item->IsPVRChannel()) + { + bValue = item->GetPVRChannelInfoTag()->HasArchive(); + return true; + } + break; + case LISTITEM_ISPLAYABLE: + if (item->IsEPG()) + { + bValue = item->GetEPGInfoTag()->IsPlayable(); + return true; + } + break; + case LISTITEM_ISRECORDING: + if (item->IsPVRChannel()) + { + bValue = CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel( + *item->GetPVRChannelInfoTag()); + return true; + } + else if (item->IsEPG() || item->IsPVRTimer()) + { + const std::shared_ptr<CPVRTimerInfoTag> timer = CPVRItem(item).GetTimerInfoTag(); + if (timer) + bValue = timer->IsRecording(); + return true; + } + else if (item->IsPVRRecording()) + { + bValue = item->GetPVRRecordingInfoTag()->IsInProgress(); + return true; + } + break; + case LISTITEM_INPROGRESS: + if (item->IsPVRChannel() || item->IsEPG()) + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = CPVRItem(item).GetEpgInfoTag(); + if (epgTag) + bValue = epgTag->IsActive(); + return true; + } + break; + case LISTITEM_HASTIMER: + if (item->IsPVRChannel() || item->IsEPG() || item->IsPVRTimer()) + { + const std::shared_ptr<CPVRTimerInfoTag> timer = CPVRItem(item).GetTimerInfoTag(); + if (timer) + bValue = true; + return true; + } + break; + case LISTITEM_HASTIMERSCHEDULE: + if (item->IsPVRChannel() || item->IsEPG() || item->IsPVRTimer()) + { + const std::shared_ptr<CPVRTimerInfoTag> timer = CPVRItem(item).GetTimerInfoTag(); + if (timer) + bValue = timer->HasParent(); + return true; + } + break; + case LISTITEM_HASREMINDER: + if (item->IsPVRChannel() || item->IsEPG() || item->IsPVRTimer()) + { + const std::shared_ptr<CPVRTimerInfoTag> timer = CPVRItem(item).GetTimerInfoTag(); + if (timer) + bValue = timer->IsReminder(); + return true; + } + break; + case LISTITEM_HASREMINDERRULE: + if (item->IsPVRChannel() || item->IsEPG() || item->IsPVRTimer()) + { + const std::shared_ptr<CPVRTimerInfoTag> timer = CPVRItem(item).GetTimerInfoTag(); + if (timer) + bValue = timer->IsReminder() && timer->HasParent(); + return true; + } + break; + case LISTITEM_TIMERISACTIVE: + if (item->IsPVRChannel() || item->IsEPG()) + { + const std::shared_ptr<CPVRTimerInfoTag> timer = CPVRItem(item).GetTimerInfoTag(); + if (timer) + bValue = timer->IsActive(); + break; + } + break; + case LISTITEM_TIMERHASCONFLICT: + if (item->IsPVRChannel() || item->IsEPG()) + { + const std::shared_ptr<CPVRTimerInfoTag> timer = CPVRItem(item).GetTimerInfoTag(); + if (timer) + bValue = timer->HasConflict(); + return true; + } + break; + case LISTITEM_TIMERHASERROR: + if (item->IsPVRChannel() || item->IsEPG()) + { + const std::shared_ptr<CPVRTimerInfoTag> timer = CPVRItem(item).GetTimerInfoTag(); + if (timer) + bValue = (timer->IsBroken() && !timer->HasConflict()); + return true; + } + break; + case LISTITEM_HASRECORDING: + if (item->IsPVRChannel() || item->IsEPG()) + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = CPVRItem(item).GetEpgInfoTag(); + if (epgTag) + bValue = !!CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(epgTag); + return true; + } + break; + case LISTITEM_HAS_EPG: + if (item->IsPVRChannel() || item->IsEPG() || item->IsPVRTimer()) + { + const std::shared_ptr<CPVREpgInfoTag> epgTag = CPVRItem(item).GetEpgInfoTag(); + bValue = (epgTag != nullptr); + return true; + } + break; + case LISTITEM_ISENCRYPTED: + if (item->IsPVRChannel() || item->IsEPG()) + { + const std::shared_ptr<CPVRChannel> channel = CPVRItem(item).GetChannel(); + if (channel) + bValue = channel->IsEncrypted(); + return true; + } + break; + case LISTITEM_IS_NEW: + if (item->IsEPG()) + { + if (item->GetEPGInfoTag()) + { + bValue = item->GetEPGInfoTag()->IsNew(); + return true; + } + } + else if (item->IsPVRRecording()) + { + bValue = item->GetPVRRecordingInfoTag()->IsNew(); + return true; + } + else if (item->IsPVRTimer() && item->GetPVRTimerInfoTag()->GetEpgInfoTag()) + { + bValue = item->GetPVRTimerInfoTag()->GetEpgInfoTag()->IsNew(); + return true; + } + else if (item->IsPVRChannel()) + { + const std::shared_ptr<CPVREpgInfoTag> epgNow = item->GetPVRChannelInfoTag()->GetEPGNow(); + bValue = epgNow ? epgNow->IsNew() : false; + return true; + } + break; + case LISTITEM_IS_PREMIERE: + if (item->IsEPG()) + { + bValue = item->GetEPGInfoTag()->IsPremiere(); + return true; + } + else if (item->IsPVRRecording()) + { + bValue = item->GetPVRRecordingInfoTag()->IsPremiere(); + return true; + } + else if (item->IsPVRTimer() && item->GetPVRTimerInfoTag()->GetEpgInfoTag()) + { + bValue = item->GetPVRTimerInfoTag()->GetEpgInfoTag()->IsPremiere(); + return true; + } + else if (item->IsPVRChannel()) + { + const std::shared_ptr<CPVREpgInfoTag> epgNow = item->GetPVRChannelInfoTag()->GetEPGNow(); + bValue = epgNow ? epgNow->IsPremiere() : false; + return true; + } + break; + case LISTITEM_IS_FINALE: + if (item->IsEPG()) + { + bValue = item->GetEPGInfoTag()->IsFinale(); + return true; + } + else if (item->IsPVRRecording()) + { + bValue = item->GetPVRRecordingInfoTag()->IsFinale(); + return true; + } + else if (item->IsPVRTimer() && item->GetPVRTimerInfoTag()->GetEpgInfoTag()) + { + bValue = item->GetPVRTimerInfoTag()->GetEpgInfoTag()->IsFinale(); + return true; + } + else if (item->IsPVRChannel()) + { + const std::shared_ptr<CPVREpgInfoTag> epgNow = item->GetPVRChannelInfoTag()->GetEPGNow(); + bValue = epgNow ? epgNow->IsFinale() : false; + return true; + } + break; + case LISTITEM_IS_LIVE: + if (item->IsEPG()) + { + bValue = item->GetEPGInfoTag()->IsLive(); + return true; + } + else if (item->IsPVRRecording()) + { + bValue = item->GetPVRRecordingInfoTag()->IsLive(); + return true; + } + else if (item->IsPVRTimer() && item->GetPVRTimerInfoTag()->GetEpgInfoTag()) + { + bValue = item->GetPVRTimerInfoTag()->GetEpgInfoTag()->IsLive(); + return true; + } + else if (item->IsPVRChannel()) + { + const std::shared_ptr<CPVREpgInfoTag> epgNow = item->GetPVRChannelInfoTag()->GetEPGNow(); + bValue = epgNow ? epgNow->IsLive() : false; + return true; + } + break; + case MUSICPLAYER_CONTENT: + case VIDEOPLAYER_CONTENT: + if (item->IsPVRChannel()) + { + bValue = StringUtils::EqualsNoCase(info.GetData3(), "livetv"); + return bValue; // if no match for this provider, other providers shall be asked. + } + break; + case VIDEOPLAYER_HAS_INFO: + if (item->IsPVRChannel()) + { + bValue = !item->GetPVRChannelInfoTag()->ChannelName().empty(); + return true; + } + break; + case VIDEOPLAYER_HAS_EPG: + if (item->IsPVRChannel()) + { + bValue = (item->GetPVRChannelInfoTag()->GetEPGNow() != nullptr); + return true; + } + break; + case VIDEOPLAYER_CAN_RESUME_LIVE_TV: + if (item->IsPVRRecording()) + { + const std::shared_ptr<CPVRRecording> recording = item->GetPVRRecordingInfoTag(); + const std::shared_ptr<CPVREpg> epg = + recording->Channel() ? recording->Channel()->GetEPG() : nullptr; + const std::shared_ptr<CPVREpgInfoTag> epgTag = + CServiceBroker::GetPVRManager().EpgContainer().GetTagById(epg, + recording->BroadcastUid()); + bValue = (epgTag && epgTag->IsActive()); + return true; + } + break; + case PLAYER_IS_CHANNEL_PREVIEW_ACTIVE: + if (item->IsPVRChannel()) + { + if (m_previewAndPlayerShowInfo) + { + bValue = true; + } + else + { + bValue = !m_videoInfo.valid; + if (bValue && item->GetPVRChannelInfoTag()->IsRadio()) + bValue = !m_audioInfo.valid; + } + return true; + } + break; + } + return false; +} + +bool CPVRGUIInfo::GetPVRBool(const CFileItem* item, const CGUIInfo& info, bool& bValue) const +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + switch (info.m_info) + { + case PVR_IS_RECORDING: + bValue = m_anyTimersInfo.HasRecordingTimers(); + return true; + case PVR_IS_RECORDING_TV: + bValue = m_tvTimersInfo.HasRecordingTimers(); + return true; + case PVR_IS_RECORDING_RADIO: + bValue = m_radioTimersInfo.HasRecordingTimers(); + return true; + case PVR_HAS_TIMER: + bValue = m_anyTimersInfo.HasTimers(); + return true; + case PVR_HAS_TV_TIMER: + bValue = m_tvTimersInfo.HasTimers(); + return true; + case PVR_HAS_RADIO_TIMER: + bValue = m_radioTimersInfo.HasTimers(); + return true; + case PVR_HAS_TV_CHANNELS: + bValue = m_bHasTVChannels; + return true; + case PVR_HAS_RADIO_CHANNELS: + bValue = m_bHasRadioChannels; + return true; + case PVR_HAS_NONRECORDING_TIMER: + bValue = m_anyTimersInfo.HasNonRecordingTimers(); + return true; + case PVR_HAS_NONRECORDING_TV_TIMER: + bValue = m_tvTimersInfo.HasNonRecordingTimers(); + return true; + case PVR_HAS_NONRECORDING_RADIO_TIMER: + bValue = m_radioTimersInfo.HasNonRecordingTimers(); + return true; + case PVR_IS_PLAYING_TV: + bValue = m_bIsPlayingTV; + return true; + case PVR_IS_PLAYING_RADIO: + bValue = m_bIsPlayingRadio; + return true; + case PVR_IS_PLAYING_RECORDING: + bValue = m_bIsPlayingRecording; + return true; + case PVR_IS_PLAYING_EPGTAG: + bValue = m_bIsPlayingEpgTag; + return true; + case PVR_ACTUAL_STREAM_ENCRYPTED: + bValue = m_bIsPlayingEncryptedStream; + return true; + case PVR_IS_TIMESHIFTING: + bValue = m_timesInfo.IsTimeshifting(); + return true; + case PVR_CAN_RECORD_PLAYING_CHANNEL: + bValue = m_bCanRecordPlayingChannel; + return true; + case PVR_IS_RECORDING_PLAYING_CHANNEL: + bValue = m_bIsRecordingPlayingChannel; + return true; + case PVR_IS_PLAYING_ACTIVE_RECORDING: + bValue = m_bIsPlayingActiveRecording; + return true; + } + return false; +} + +bool CPVRGUIInfo::GetRadioRDSBool(const CFileItem* item, const CGUIInfo& info, bool& bValue) const +{ + if (!item->HasPVRChannelInfoTag()) + return false; + + const std::shared_ptr<CPVRRadioRDSInfoTag> tag = + item->GetPVRChannelInfoTag()->GetRadioRDSInfoTag(); + if (tag) + { + switch (info.m_info) + { + case RDS_HAS_RADIOTEXT: + bValue = tag->IsPlayingRadioText(); + return true; + case RDS_HAS_RADIOTEXT_PLUS: + bValue = tag->IsPlayingRadioTextPlus(); + return true; + case RDS_HAS_HOTLINE_DATA: + bValue = (!tag->GetEMailHotline().empty() || !tag->GetPhoneHotline().empty()); + return true; + case RDS_HAS_STUDIO_DATA: + bValue = (!tag->GetEMailStudio().empty() || !tag->GetSMSStudio().empty() || + !tag->GetPhoneStudio().empty()); + return true; + } + } + + switch (info.m_info) + { + case RDS_HAS_RDS: + { + const auto& components = CServiceBroker::GetAppComponents(); + const auto appPlayer = components.GetComponent<CApplicationPlayer>(); + bValue = appPlayer->IsPlayingRDS(); + return true; + } + } + + return false; +} + +void CPVRGUIInfo::CharInfoBackendNumber(std::string& strValue) const +{ + size_t numBackends = m_backendProperties.size(); + + if (numBackends > 0) + strValue = StringUtils::Format("{0} {1} {2}", m_iCurrentActiveClient + 1, + g_localizeStrings.Get(20163), numBackends); + else + strValue = g_localizeStrings.Get(14023); +} + +void CPVRGUIInfo::CharInfoTotalDiskSpace(std::string& strValue) const +{ + strValue = StringUtils::SizeToString(m_iBackendDiskTotal).c_str(); +} + +void CPVRGUIInfo::CharInfoSignal(std::string& strValue) const +{ + strValue = StringUtils::Format("{} %", m_qualityInfo.iSignal / 655); +} + +void CPVRGUIInfo::CharInfoSNR(std::string& strValue) const +{ + strValue = StringUtils::Format("{} %", m_qualityInfo.iSNR / 655); +} + +void CPVRGUIInfo::CharInfoBER(std::string& strValue) const +{ + strValue = StringUtils::Format("{:08X}", m_qualityInfo.iBER); +} + +void CPVRGUIInfo::CharInfoUNC(std::string& strValue) const +{ + strValue = StringUtils::Format("{:08X}", m_qualityInfo.iUNC); +} + +void CPVRGUIInfo::CharInfoFrontendName(std::string& strValue) const +{ + if (!strlen(m_qualityInfo.strAdapterName)) + strValue = g_localizeStrings.Get(13205); + else + strValue = m_qualityInfo.strAdapterName; +} + +void CPVRGUIInfo::CharInfoFrontendStatus(std::string& strValue) const +{ + if (!strlen(m_qualityInfo.strAdapterStatus)) + strValue = g_localizeStrings.Get(13205); + else + strValue = m_qualityInfo.strAdapterStatus; +} + +void CPVRGUIInfo::CharInfoBackendName(std::string& strValue) const +{ + m_updateBackendCacheRequested = true; + strValue = m_strBackendName; +} + +void CPVRGUIInfo::CharInfoBackendVersion(std::string& strValue) const +{ + m_updateBackendCacheRequested = true; + strValue = m_strBackendVersion; +} + +void CPVRGUIInfo::CharInfoBackendHost(std::string& strValue) const +{ + m_updateBackendCacheRequested = true; + strValue = m_strBackendHost; +} + +void CPVRGUIInfo::CharInfoBackendDiskspace(std::string& strValue) const +{ + m_updateBackendCacheRequested = true; + + auto diskTotal = m_iBackendDiskTotal; + auto diskUsed = m_iBackendDiskUsed; + + if (diskTotal > 0) + { + strValue = StringUtils::Format(g_localizeStrings.Get(802), + StringUtils::SizeToString(diskTotal - diskUsed), + StringUtils::SizeToString(diskTotal)); + } + else + strValue = g_localizeStrings.Get(13205); +} + +void CPVRGUIInfo::CharInfoBackendProviders(std::string& strValue) const +{ + m_updateBackendCacheRequested = true; + strValue = m_strBackendProviders; +} + +void CPVRGUIInfo::CharInfoBackendChannelGroups(std::string& strValue) const +{ + m_updateBackendCacheRequested = true; + strValue = m_strBackendChannelGroups; +} + +void CPVRGUIInfo::CharInfoBackendChannels(std::string& strValue) const +{ + m_updateBackendCacheRequested = true; + strValue = m_strBackendChannels; +} + +void CPVRGUIInfo::CharInfoBackendTimers(std::string& strValue) const +{ + m_updateBackendCacheRequested = true; + strValue = m_strBackendTimers; +} + +void CPVRGUIInfo::CharInfoBackendRecordings(std::string& strValue) const +{ + m_updateBackendCacheRequested = true; + strValue = m_strBackendRecordings; +} + +void CPVRGUIInfo::CharInfoBackendDeletedRecordings(std::string& strValue) const +{ + m_updateBackendCacheRequested = true; + strValue = m_strBackendDeletedRecordings; +} + +void CPVRGUIInfo::CharInfoPlayingClientName(std::string& strValue) const +{ + if (m_strPlayingClientName.empty()) + strValue = g_localizeStrings.Get(13205); + else + strValue = m_strPlayingClientName; +} + +void CPVRGUIInfo::CharInfoEncryption(std::string& strValue) const +{ + if (m_descrambleInfo.iCaid != PVR_DESCRAMBLE_INFO_NOT_AVAILABLE) + { + // prefer dynamically updated info, if available + strValue = CPVRChannel::GetEncryptionName(m_descrambleInfo.iCaid); + return; + } + else + { + const std::shared_ptr<CPVRChannel> channel = + CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel(); + if (channel) + { + strValue = channel->EncryptionName(); + return; + } + } + + strValue.clear(); +} + +void CPVRGUIInfo::CharInfoService(std::string& strValue) const +{ + if (!strlen(m_qualityInfo.strServiceName)) + strValue = g_localizeStrings.Get(13205); + else + strValue = m_qualityInfo.strServiceName; +} + +void CPVRGUIInfo::CharInfoMux(std::string& strValue) const +{ + if (!strlen(m_qualityInfo.strMuxName)) + strValue = g_localizeStrings.Get(13205); + else + strValue = m_qualityInfo.strMuxName; +} + +void CPVRGUIInfo::CharInfoProvider(std::string& strValue) const +{ + if (!strlen(m_qualityInfo.strProviderName)) + strValue = g_localizeStrings.Get(13205); + else + strValue = m_qualityInfo.strProviderName; +} + +void CPVRGUIInfo::UpdateBackendCache() +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + // Update the backend information for all backends if + // an update has been requested + if (m_iCurrentActiveClient == 0 && m_updateBackendCacheRequested) + { + std::vector<SBackend> backendProperties; + { + CSingleExit exit(m_critSection); + backendProperties = CServiceBroker::GetPVRManager().Clients()->GetBackendProperties(); + } + + m_backendProperties = backendProperties; + m_updateBackendCacheRequested = false; + } + + // Store some defaults + m_strBackendName = g_localizeStrings.Get(13205); + m_strBackendVersion = g_localizeStrings.Get(13205); + m_strBackendHost = g_localizeStrings.Get(13205); + m_strBackendProviders = g_localizeStrings.Get(13205); + m_strBackendChannelGroups = g_localizeStrings.Get(13205); + m_strBackendChannels = g_localizeStrings.Get(13205); + m_strBackendTimers = g_localizeStrings.Get(13205); + m_strBackendRecordings = g_localizeStrings.Get(13205); + m_strBackendDeletedRecordings = g_localizeStrings.Get(13205); + m_iBackendDiskTotal = 0; + m_iBackendDiskUsed = 0; + + // Update with values from the current client when we have at least one + if (!m_backendProperties.empty()) + { + const auto& backend = m_backendProperties[m_iCurrentActiveClient]; + + m_strBackendName = backend.name; + m_strBackendVersion = backend.version; + m_strBackendHost = backend.host; + + // We always display one extra as the add-on itself counts as a provider + if (backend.numProviders >= 0) + m_strBackendProviders = std::to_string(backend.numProviders + 1); + + if (backend.numChannelGroups >= 0) + m_strBackendChannelGroups = std::to_string(backend.numChannelGroups); + + if (backend.numChannels >= 0) + m_strBackendChannels = std::to_string(backend.numChannels); + + if (backend.numTimers >= 0) + m_strBackendTimers = std::to_string(backend.numTimers); + + if (backend.numRecordings >= 0) + m_strBackendRecordings = std::to_string(backend.numRecordings); + + if (backend.numDeletedRecordings >= 0) + m_strBackendDeletedRecordings = std::to_string(backend.numDeletedRecordings); + + m_iBackendDiskTotal = backend.diskTotal; + m_iBackendDiskUsed = backend.diskUsed; + } + + // Update the current active client, eventually wrapping around + if (++m_iCurrentActiveClient >= m_backendProperties.size()) + m_iCurrentActiveClient = 0; +} + +void CPVRGUIInfo::UpdateTimersCache() +{ + m_anyTimersInfo.UpdateTimersCache(); + m_tvTimersInfo.UpdateTimersCache(); + m_radioTimersInfo.UpdateTimersCache(); +} + +void CPVRGUIInfo::UpdateTimersToggle() +{ + m_anyTimersInfo.UpdateTimersToggle(); + m_tvTimersInfo.UpdateTimersToggle(); + m_radioTimersInfo.UpdateTimersToggle(); +} + +void CPVRGUIInfo::UpdateNextTimer() +{ + m_anyTimersInfo.UpdateNextTimer(); + m_tvTimersInfo.UpdateNextTimer(); + m_radioTimersInfo.UpdateNextTimer(); +} + +int CPVRGUIInfo::GetTimeShiftSeekPercent() const +{ + int progress = m_timesInfo.GetTimeshiftProgressPlayPosition(); + + const auto& components = CServiceBroker::GetAppComponents(); + const auto appPlayer = components.GetComponent<CApplicationPlayer>(); + int seekSize = appPlayer->GetSeekHandler().GetSeekSize(); + if (seekSize != 0) + { + int total = m_timesInfo.GetTimeshiftProgressDuration(); + + float totalTime = static_cast<float>(total); + if (totalTime == 0.0f) + return 0; + + float percentPerSecond = 100.0f / totalTime; + float percent = progress + percentPerSecond * seekSize; + percent = std::max(0.0f, std::min(percent, 100.0f)); + return std::lrintf(percent); + } + return progress; +} |