diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/pvr/guilib/PVRGUIActionsChannels.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/pvr/guilib/PVRGUIActionsChannels.cpp')
-rw-r--r-- | xbmc/pvr/guilib/PVRGUIActionsChannels.cpp | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/xbmc/pvr/guilib/PVRGUIActionsChannels.cpp b/xbmc/pvr/guilib/PVRGUIActionsChannels.cpp new file mode 100644 index 0000000..80fb90e --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsChannels.cpp @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2016-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 "PVRGUIActionsChannels.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "dialogs/GUIDialogSelect.h" +#include "dialogs/GUIDialogYesNo.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/WindowIDs.h" +#include "input/actions/Action.h" +#include "input/actions/ActionIDs.h" +#include "messaging/ApplicationMessenger.h" +#include "messaging/helpers/DialogOKHelper.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/PVRChannelGroups.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/epg/EpgInfoTag.h" +#include "pvr/windows/GUIWindowPVRBase.h" +#include "settings/Settings.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include <algorithm> +#include <chrono> +#include <memory> +#include <mutex> +#include <string> +#include <vector> + +using namespace PVR; +using namespace KODI::MESSAGING; + +void CPVRChannelSwitchingInputHandler::AppendChannelNumberCharacter(char cCharacter) +{ + // special case. if only a single zero was typed in, switch to previously played channel. + if (GetCurrentDigitCount() == 0 && cCharacter == '0') + { + SwitchToPreviousChannel(); + return; + } + + CPVRChannelNumberInputHandler::AppendChannelNumberCharacter(cCharacter); +} + +void CPVRChannelSwitchingInputHandler::GetChannelNumbers(std::vector<std::string>& channelNumbers) +{ + const CPVRManager& pvrMgr = CServiceBroker::GetPVRManager(); + const std::shared_ptr<CPVRChannel> playingChannel = pvrMgr.PlaybackState()->GetPlayingChannel(); + if (playingChannel) + { + const std::shared_ptr<CPVRChannelGroup> group = + pvrMgr.ChannelGroups()->GetGroupAll(playingChannel->IsRadio()); + if (group) + group->GetChannelNumbers(channelNumbers); + } +} + +void CPVRChannelSwitchingInputHandler::OnInputDone() +{ + CPVRChannelNumber channelNumber = GetChannelNumber(); + if (channelNumber.GetChannelNumber()) + SwitchToChannel(channelNumber); +} + +void CPVRChannelSwitchingInputHandler::SwitchToChannel(const CPVRChannelNumber& channelNumber) +{ + if (channelNumber.IsValid() && CServiceBroker::GetPVRManager().PlaybackState()->IsPlaying()) + { + const std::shared_ptr<CPVRChannel> playingChannel = + CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel(); + if (playingChannel) + { + bool bRadio = playingChannel->IsRadio(); + const std::shared_ptr<CPVRChannelGroup> group = + CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(bRadio); + + if (channelNumber != group->GetChannelNumber(playingChannel)) + { + // channel number present in active group? + std::shared_ptr<CPVRChannelGroupMember> groupMember = + group->GetByChannelNumber(channelNumber); + + if (!groupMember) + { + // channel number present in any group? + const CPVRChannelGroups* groupAccess = + CServiceBroker::GetPVRManager().ChannelGroups()->Get(bRadio); + const std::vector<std::shared_ptr<CPVRChannelGroup>> groups = + groupAccess->GetMembers(true); + for (const auto& currentGroup : groups) + { + if (currentGroup == group) // we have already checked this group + continue; + + groupMember = currentGroup->GetByChannelNumber(channelNumber); + if (groupMember) + break; + } + } + + if (groupMember) + { + CServiceBroker::GetAppMessenger()->PostMsg( + TMSG_GUI_ACTION, WINDOW_INVALID, -1, + static_cast<void*>(new CAction( + ACTION_CHANNEL_SWITCH, static_cast<float>(channelNumber.GetChannelNumber()), + static_cast<float>(channelNumber.GetSubChannelNumber())))); + } + } + } + } +} + +void CPVRChannelSwitchingInputHandler::SwitchToPreviousChannel() +{ + const std::shared_ptr<CPVRPlaybackState> playbackState = + CServiceBroker::GetPVRManager().PlaybackState(); + if (playbackState->IsPlaying()) + { + const std::shared_ptr<CPVRChannel> playingChannel = playbackState->GetPlayingChannel(); + if (playingChannel) + { + const std::shared_ptr<CPVRChannelGroupMember> groupMember = + playbackState->GetPreviousToLastPlayedChannelGroupMember(playingChannel->IsRadio()); + if (groupMember) + { + const CPVRChannelNumber channelNumber = groupMember->ChannelNumber(); + CServiceBroker::GetAppMessenger()->SendMsg( + TMSG_GUI_ACTION, WINDOW_INVALID, -1, + static_cast<void*>(new CAction( + ACTION_CHANNEL_SWITCH, static_cast<float>(channelNumber.GetChannelNumber()), + static_cast<float>(channelNumber.GetSubChannelNumber())))); + } + } + } +} + +CPVRGUIActionsChannels::CPVRGUIActionsChannels() + : m_settings({CSettings::SETTING_PVRMANAGER_PRESELECTPLAYINGCHANNEL}) +{ + RegisterChannelNumberInputHandler(&m_channelNumberInputHandler); +} + +CPVRGUIActionsChannels::~CPVRGUIActionsChannels() +{ + DeregisterChannelNumberInputHandler(&m_channelNumberInputHandler); +} + +void CPVRGUIActionsChannels::RegisterChannelNumberInputHandler( + CPVRChannelNumberInputHandler* handler) +{ + if (handler) + handler->Events().Subscribe(this, &CPVRGUIActionsChannels::Notify); +} + +void CPVRGUIActionsChannels::DeregisterChannelNumberInputHandler( + CPVRChannelNumberInputHandler* handler) +{ + if (handler) + handler->Events().Unsubscribe(this); +} + +void CPVRGUIActionsChannels::Notify(const PVRChannelNumberInputChangedEvent& event) +{ + m_events.Publish(event); +} + +bool CPVRGUIActionsChannels::HideChannel(const CFileItem& item) const +{ + const std::shared_ptr<CPVRChannel> channel = item.GetPVRChannelInfoTag(); + + if (!channel) + return false; + + if (!CGUIDialogYesNo::ShowAndGetInput( + CVariant{19054}, // "Hide channel" + CVariant{19039}, // "Are you sure you want to hide this channel?" + CVariant{""}, CVariant{channel->ChannelName()})) + return false; + + if (!CServiceBroker::GetPVRManager() + .ChannelGroups() + ->GetGroupAll(channel->IsRadio()) + ->RemoveFromGroup(channel)) + return false; + + CGUIWindowPVRBase* pvrWindow = + dynamic_cast<CGUIWindowPVRBase*>(CServiceBroker::GetGUI()->GetWindowManager().GetWindow( + CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow())); + if (pvrWindow) + pvrWindow->DoRefresh(); + else + CLog::LogF(LOGERROR, "Called on non-pvr window. No refresh possible."); + + return true; +} + +bool CPVRGUIActionsChannels::StartChannelScan() +{ + return StartChannelScan(PVR_INVALID_CLIENT_ID); +} + +bool CPVRGUIActionsChannels::StartChannelScan(int clientId) +{ + if (!CServiceBroker::GetPVRManager().IsStarted() || IsRunningChannelScan()) + return false; + + std::shared_ptr<CPVRClient> scanClient; + std::vector<std::shared_ptr<CPVRClient>> possibleScanClients = + CServiceBroker::GetPVRManager().Clients()->GetClientsSupportingChannelScan(); + m_bChannelScanRunning = true; + + if (clientId != PVR_INVALID_CLIENT_ID) + { + const auto it = + std::find_if(possibleScanClients.cbegin(), possibleScanClients.cend(), + [clientId](const auto& client) { return client->GetID() == clientId; }); + + if (it != possibleScanClients.cend()) + scanClient = (*it); + + if (!scanClient) + { + CLog::LogF(LOGERROR, + "Provided client id '{}' could not be found in list of possible scan clients!", + clientId); + m_bChannelScanRunning = false; + return false; + } + } + /* multiple clients found */ + else if (possibleScanClients.size() > 1) + { + CGUIDialogSelect* pDialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>( + WINDOW_DIALOG_SELECT); + if (!pDialog) + { + CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT!"); + m_bChannelScanRunning = false; + return false; + } + + pDialog->Reset(); + pDialog->SetHeading(CVariant{19119}); // "On which backend do you want to search?" + + for (const auto& client : possibleScanClients) + pDialog->Add(client->GetFriendlyName()); + + pDialog->Open(); + + int selection = pDialog->GetSelectedItem(); + if (selection >= 0) + scanClient = possibleScanClients[selection]; + } + /* one client found */ + else if (possibleScanClients.size() == 1) + { + scanClient = possibleScanClients[0]; + } + /* no clients found */ + else if (!scanClient) + { + HELPERS::ShowOKDialogText( + CVariant{19033}, // "Information" + CVariant{19192}); // "None of the connected PVR backends supports scanning for channels." + m_bChannelScanRunning = false; + return false; + } + + /* start the channel scan */ + CLog::LogFC(LOGDEBUG, LOGPVR, "Starting to scan for channels on client {}", + scanClient->GetFriendlyName()); + auto start = std::chrono::steady_clock::now(); + + /* do the scan */ + if (scanClient->StartChannelScan() != PVR_ERROR_NO_ERROR) + HELPERS::ShowOKDialogText( + CVariant{257}, // "Error" + CVariant{ + 19193}); // "The channel scan can't be started. Check the log for more information about this message." + + auto end = std::chrono::steady_clock::now(); + auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); + + CLog::LogFC(LOGDEBUG, LOGPVR, "Channel scan finished after {} ms", duration.count()); + + m_bChannelScanRunning = false; + return true; +} + +std::shared_ptr<CPVRChannelGroupMember> CPVRGUIActionsChannels::GetChannelGroupMember( + const std::shared_ptr<CPVRChannel>& channel) const +{ + if (!channel) + return {}; + + std::shared_ptr<CPVRChannelGroupMember> groupMember; + + // first, try whether the channel is contained in the active channel group, except + // if a window is active which never uses the active channel group, e.g. Timers window + const int activeWindowID = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow(); + + static std::vector<int> windowIDs = { + WINDOW_TV_RECORDINGS, WINDOW_TV_TIMERS, WINDOW_TV_TIMER_RULES, WINDOW_TV_SEARCH, + WINDOW_RADIO_RECORDINGS, WINDOW_RADIO_TIMERS, WINDOW_RADIO_TIMER_RULES, WINDOW_RADIO_SEARCH, + }; + + if (std::find(windowIDs.cbegin(), windowIDs.cend(), activeWindowID) == windowIDs.cend()) + { + const std::shared_ptr<CPVRChannelGroup> group = + CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(channel->IsRadio()); + if (group) + groupMember = group->GetByUniqueID(channel->StorageId()); + } + + // as fallback, obtain the member from the 'all channels' group + if (!groupMember) + { + const std::shared_ptr<CPVRChannelGroup> group = + CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(channel->IsRadio()); + if (group) + groupMember = group->GetByUniqueID(channel->StorageId()); + } + + return groupMember; +} + +std::shared_ptr<CPVRChannelGroupMember> CPVRGUIActionsChannels::GetChannelGroupMember( + const CFileItem& item) const +{ + std::shared_ptr<CPVRChannelGroupMember> groupMember = item.GetPVRChannelGroupMemberInfoTag(); + + if (!groupMember) + groupMember = GetChannelGroupMember(CPVRItem(std::make_shared<CFileItem>(item)).GetChannel()); + + return groupMember; +} + +CPVRChannelNumberInputHandler& CPVRGUIActionsChannels::GetChannelNumberInputHandler() +{ + // window/dialog specific input handler + CPVRChannelNumberInputHandler* windowInputHandler = dynamic_cast<CPVRChannelNumberInputHandler*>( + CServiceBroker::GetGUI()->GetWindowManager().GetWindow( + CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog())); + if (windowInputHandler) + return *windowInputHandler; + + // default + return m_channelNumberInputHandler; +} + +CPVRGUIChannelNavigator& CPVRGUIActionsChannels::GetChannelNavigator() +{ + return m_channelNavigator; +} + +void CPVRGUIActionsChannels::OnPlaybackStarted(const CFileItem& item) +{ + const std::shared_ptr<CPVRChannelGroupMember> groupMember = GetChannelGroupMember(item); + if (groupMember) + { + m_channelNavigator.SetPlayingChannel(groupMember); + SetSelectedChannelPath(groupMember->Channel()->IsRadio(), groupMember->Path()); + } +} + +void CPVRGUIActionsChannels::OnPlaybackStopped(const CFileItem& item) +{ + if (item.HasPVRChannelInfoTag() || item.HasEPGInfoTag()) + { + m_channelNavigator.ClearPlayingChannel(); + } +} + +void CPVRGUIActionsChannels::SetSelectedChannelPath(bool bRadio, const std::string& path) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + if (bRadio) + m_selectedChannelPathRadio = path; + else + m_selectedChannelPathTV = path; +} + +std::string CPVRGUIActionsChannels::GetSelectedChannelPath(bool bRadio) const +{ + if (m_settings.GetBoolValue(CSettings::SETTING_PVRMANAGER_PRESELECTPLAYINGCHANNEL)) + { + CPVRManager& mgr = CServiceBroker::GetPVRManager(); + + // if preselect playing channel is activated, return the path of the playing channel, if any. + const std::shared_ptr<CPVRChannelGroupMember> playingChannel = + mgr.PlaybackState()->GetPlayingChannelGroupMember(); + if (playingChannel && playingChannel->IsRadio() == bRadio) + return playingChannel->Path(); + + const std::shared_ptr<CPVREpgInfoTag> playingTag = mgr.PlaybackState()->GetPlayingEpgTag(); + if (playingTag && playingTag->IsRadio() == bRadio) + { + const std::shared_ptr<CPVRChannel> channel = + mgr.ChannelGroups()->GetChannelForEpgTag(playingTag); + if (channel) + return GetChannelGroupMember(channel)->Path(); + } + } + + std::unique_lock<CCriticalSection> lock(m_critSection); + return bRadio ? m_selectedChannelPathRadio : m_selectedChannelPathTV; +} |