CPVREpgInfoTagPtr CPVREpg::GetTagNow(bool bUpdateIfNeeded /* = true */) const { CSingleLock lock(m_critSection); if (m_nowActiveStart.IsValid()) { std::map<CDateTime, CPVREpgInfoTagPtr>::const_iterator it = m_tags.find(m_nowActiveStart); if (it != m_tags.end() && it->second->IsActive()) return it->second; } if (bUpdateIfNeeded) { CPVREpgInfoTagPtr lastActiveTag; /* one of the first items will always match if the list is sorted */ for (std::map<CDateTime, CPVREpgInfoTagPtr>::const_iterator it = m_tags.begin(); it != m_tags.end(); ++it) { if (it->second->IsActive()) { m_nowActiveStart = it->first; return it->second; } else if (it->second->WasActive()) lastActiveTag = it->second; } /* there might be a gap between the last and next event. return the last if found and it ended not more than 5 minutes ago */ if (lastActiveTag && lastActiveTag->EndAsUTC() + CDateTimeSpan(0, 0, 5, 0) >= CDateTime::GetUTCDateTime()) return lastActiveTag; } return CPVREpgInfoTagPtr(); }
void CPVRChannel::Serialize(CVariant& value) const { value["channelid"] = m_iChannelId; value["channeltype"] = m_bIsRadio ? "radio" : "tv"; value["hidden"] = m_bIsHidden; value["locked"] = m_bIsLocked; value["icon"] = m_strIconPath; value["channel"] = m_strChannelName; value["uniqueid"] = m_iUniqueId; CDateTime lastPlayed(m_iLastWatched); value["lastplayed"] = lastPlayed.IsValid() ? lastPlayed.GetAsDBDate() : ""; value["channelnumber"] = m_channelNumber.GetChannelNumber(); value["subchannelnumber"] = m_channelNumber.GetSubChannelNumber(); CPVREpgInfoTagPtr epg = GetEPGNow(); if (epg) { // add the properties of the current EPG item to the main object epg->Serialize(value); // and add an extra sub-object with only the current EPG details epg->Serialize(value["broadcastnow"]); } epg = GetEPGNext(); if (epg) epg->Serialize(value["broadcastnext"]); value["isrecording"] = false; // compat }
CPVRRecordingPtr CPVRRecordings::GetRecordingForEpgTag(const CPVREpgInfoTagPtr &epgTag) const { if (!epgTag) return {}; CSingleLock lock(m_critSection); for (const auto recording : m_recordings) { if (recording.second->IsDeleted()) continue; if (recording.second->ClientID() != epgTag->ClientID()) continue; if (recording.second->ChannelUid() != epgTag->UniqueChannelID()) continue; unsigned int iEpgEvent = recording.second->BroadcastUid(); if (iEpgEvent != EPG_TAG_INVALID_UID) { if (iEpgEvent == epgTag->UniqueBroadcastID()) return recording.second; } else { if (recording.second->RecordingTimeAsUTC() <= epgTag->StartAsUTC() && recording.second->EndTimeAsUTC() >= epgTag->EndAsUTC()) return recording.second; } } return CPVRRecordingPtr(); }
CPVRTimerInfoTagPtr CPVRTimers::GetTimerForEpgTag(const CPVREpgInfoTagPtr &epgTag) const { if (epgTag) { CSingleLock lock(m_critSection); for (const auto &tagsEntry : m_tags) { for (const auto &timersEntry : tagsEntry.second) { if (timersEntry->IsTimerRule()) continue; if (timersEntry->GetEpgInfoTag(false) == epgTag) return timersEntry; if (timersEntry->m_iClientChannelUid != PVR_CHANNEL_INVALID_UID && timersEntry->m_iClientChannelUid == epgTag->UniqueChannelID()) { if (timersEntry->UniqueBroadcastID() != EPG_TAG_INVALID_UID && timersEntry->UniqueBroadcastID() == epgTag->UniqueBroadcastID()) return timersEntry; if (timersEntry->m_bIsRadio == epgTag->IsRadio() && timersEntry->StartAsUTC() <= epgTag->StartAsUTC() && timersEntry->EndAsUTC() >= epgTag->EndAsUTC()) return timersEntry; } } } } return CPVRTimerInfoTagPtr(); }
int CPVRChannelGroup::GetEPGNowOrNext(CFileItemList &results, bool bGetNext) const { int iInitialSize = results.Size(); CPVREpgInfoTagPtr epgNext; CPVRChannelPtr channel; CSingleLock lock(m_critSection); for (PVR_CHANNEL_GROUP_SORTED_MEMBERS::const_iterator it = m_sortedMembers.begin(); it != m_sortedMembers.end(); ++it) { channel = (*it).channel; CPVREpgPtr epg = channel->GetEPG(); if (epg && !channel->IsHidden()) { epgNext = bGetNext ? epg->GetTagNext() : epg->GetTagNow(); if (epgNext) { CFileItemPtr entry(new CFileItem(epgNext)); entry->SetLabel2(epgNext->StartAsLocalTime().GetAsLocalizedTime("", false)); entry->SetPath(channel->Path()); entry->SetArt("thumb", channel->IconPath()); results.Add(entry); } } } return results.Size() - iInitialSize; }
int CPVRChannelGroup::GetEPGAll(CFileItemList &results, bool bIncludeChannelsWithoutEPG /* = false */) const { int iInitialSize = results.Size(); CPVREpgInfoTagPtr epgTag; CPVRChannelPtr channel; CSingleLock lock(m_critSection); for (PVR_CHANNEL_GROUP_SORTED_MEMBERS::const_iterator it = m_sortedMembers.begin(); it != m_sortedMembers.end(); ++it) { channel = (*it).channel; if (!channel->IsHidden()) { int iAdded = 0; CPVREpgPtr epg = channel->GetEPG(); if (epg) { // XXX channel pointers aren't set in some occasions. this works around the issue, but is not very nice epg->SetChannel(channel); iAdded = epg->Get(results); } if (bIncludeChannelsWithoutEPG && iAdded == 0) { // Add dummy EPG tag associated with this channel epgTag = CPVREpgInfoTag::CreateDefaultTag(); epgTag->SetChannel(channel); results.Add(CFileItemPtr(new CFileItem(epgTag))); } } } return results.Size() - iInitialSize; }
void CGUIDialogPVRTimerSettings::InitializeTypesList() { m_typeEntries.clear(); // If timer is read-only or was created by a timer rule, only add current type, for information. Type can't be changed. if (m_timerType->IsReadOnly() || m_timerInfoTag->GetTimerRuleId() != PVR_TIMER_NO_PARENT) { m_typeEntries.insert(std::make_pair(0, m_timerType)); return; } bool bFoundThisType(false); int idx(0); const std::vector<CPVRTimerTypePtr> types(CPVRTimerType::GetAllTypes()); for (const auto &type : types) { // Type definition prohibits created of new instances. // But the dialog can act as a viewer for these types. if (type->ForbidsNewInstances()) continue; // Read-only timers cannot be created using this dialog. // But the dialog can act as a viewer for read-only types. if (type->IsReadOnly()) continue; // Drop TimerTypes that require EPGInfo, if none is populated if (type->RequiresEpgTagOnCreate() && !m_timerInfoTag->GetEpgInfoTag()) continue; // Drop TimerTypes without 'Series' EPG attributes if none are set if (type->RequiresEpgSeriesOnCreate()) { const CPVREpgInfoTagPtr epgTag(m_timerInfoTag->GetEpgInfoTag()); if (epgTag && !epgTag->IsSeries()) continue; } // Drop TimerTypes that forbid EPGInfo, if it is populated if (type->ForbidsEpgTagOnCreate() && m_timerInfoTag->GetEpgInfoTag()) continue; // Drop TimerTypes that aren't rules if end time is in the past if (!type->IsTimerRule() && m_timerInfoTag->EndAsLocalTime() < CDateTime::GetCurrentDateTime()) continue; if (!bFoundThisType && *type == *m_timerType) bFoundThisType = true; m_typeEntries.insert(std::make_pair(idx++, type)); } if (!bFoundThisType) m_typeEntries.insert(std::make_pair(idx++, m_timerType)); }
bool CPVREpgSearchFilter::MatchDuration(const CPVREpgInfoTagPtr &tag) const { bool bReturn(true); if (m_iMinimumDuration != EPG_SEARCH_UNSET) bReturn = (tag->GetDuration() > m_iMinimumDuration * 60); if (bReturn && m_iMaximumDuration != EPG_SEARCH_UNSET) bReturn = (tag->GetDuration() < m_iMaximumDuration * 60); return bReturn; }
void CPVRRecording::OnDelete(void) { if (m_iEpgEventId != EPG_TAG_INVALID_UID) { const CPVRChannelPtr channel(Channel()); if (channel) { const CPVREpgInfoTagPtr epgTag(CServiceBroker::GetPVRManager().EpgContainer().GetTagById(channel, m_iEpgEventId)); if (epgTag) epgTag->ClearRecording(); } } }
bool CPVREpgSearchFilter::MatchGenre(const CPVREpgInfoTagPtr &tag) const { bool bReturn(true); if (m_iGenreType != EPG_SEARCH_UNSET) { bool bIsUnknownGenre(tag->GenreType() > EPG_EVENT_CONTENTMASK_USERDEFINED || tag->GenreType() < EPG_EVENT_CONTENTMASK_MOVIEDRAMA); bReturn = ((m_bIncludeUnknownGenres && bIsUnknownGenre) || tag->GenreType() == m_iGenreType); } return bReturn; }
bool CPVREpgSearchFilter::MatchSearchTerm(const CPVREpgInfoTagPtr &tag) const { bool bReturn(true); if (!m_strSearchTerm.empty()) { CTextSearch search(m_strSearchTerm, m_bIsCaseSensitive, SEARCH_DEFAULT_OR); bReturn = search.Search(tag->Title()) || search.Search(tag->PlotOutline()) || (m_bSearchInDescription && search.Search(tag->Plot())); } return bReturn; }
int CPVREpgSearchFilter::RemoveDuplicates(CFileItemList &results) { unsigned int iSize = results.Size(); for (unsigned int iResultPtr = 0; iResultPtr < iSize; iResultPtr++) { const CPVREpgInfoTagPtr epgentry_1(results.Get(iResultPtr)->GetEPGInfoTag()); if (!epgentry_1) continue; for (unsigned int iTagPtr = 0; iTagPtr < iSize; iTagPtr++) { if (iResultPtr == iTagPtr) continue; const CPVREpgInfoTagPtr epgentry_2(results.Get(iTagPtr)->GetEPGInfoTag()); if (!epgentry_2) continue; if (epgentry_1->Title() != epgentry_2->Title() || epgentry_1->Plot() != epgentry_2->Plot() || epgentry_1->PlotOutline() != epgentry_2->PlotOutline()) continue; results.Remove(iTagPtr); iResultPtr--; iTagPtr--; iSize--; } } return iSize; }
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 CPVREpgInfoTagPtr epgTag = CPVRItem(item).GetEpgInfoTag(); if (epgTag) iValue = static_cast<int>(epgTag->ProgressPercentage()); } return true; } return false; }
bool CPVREpgSearchFilter::MatchBroadcastId(const CPVREpgInfoTagPtr &tag) const { if (m_iUniqueBroadcastId != EPG_TAG_INVALID_UID) return (tag->UniqueBroadcastID() == m_iUniqueBroadcastId); return true; }
bool CPVREpg::UpdateEntry(const CPVREpgInfoTagPtr &tag, EPG_EVENT_STATE newState, bool bUpdateDatabase) { bool bRet(true); bool bNotify(true); if (newState == EPG_EVENT_CREATED || newState == EPG_EVENT_UPDATED) { bRet = UpdateEntry(tag, bUpdateDatabase); } else if (newState == EPG_EVENT_DELETED) { CSingleLock lock(m_critSection); auto it = m_tags.begin(); for (; it != m_tags.end(); ++it) { if (it->second->UniqueBroadcastID() == tag->UniqueBroadcastID()) break; } if (it == m_tags.end()) { bRet = false; } else { // Respect epg linger time. int iPastDays = CServiceBroker::GetPVRManager().EpgContainer().GetPastDaysToDisplay(); const CDateTime cleanupTime(CDateTime::GetUTCDateTime() - CDateTimeSpan(iPastDays, 0, 0, 0)); if (it->second->EndAsUTC() < cleanupTime) { if (bUpdateDatabase) m_deletedTags.insert(std::make_pair(it->second->UniqueBroadcastID(), it->second)); it->second->ClearTimer(); it->second->ClearRecording(); m_tags.erase(it); } else { bNotify = false; } } } else { CLog::Log(LOGERROR, "EPG - %s - unknown epg event state value: %d", __FUNCTION__, newState); bRet = false; } if (bRet && bNotify) { SetChanged(); NotifyObservers(ObservableMessageEpgItemUpdate); } return bRet; }
void CPVREpg::AddEntry(const CPVREpgInfoTag &tag) { CPVREpgInfoTagPtr newTag; CPVRChannelPtr channel; { CSingleLock lock(m_critSection); std::map<CDateTime, CPVREpgInfoTagPtr>::iterator itr = m_tags.find(tag.StartAsUTC()); if (itr != m_tags.end()) newTag = itr->second; else { newTag.reset(new CPVREpgInfoTag(this, m_pvrChannel, m_strName, m_pvrChannel ? m_pvrChannel->IconPath() : "")); m_tags.insert(make_pair(tag.StartAsUTC(), newTag)); } channel = m_pvrChannel; } if (newTag) { newTag->Update(tag); newTag->SetChannel(channel); newTag->SetEpg(this); newTag->SetTimer(CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(newTag)); newTag->SetRecording(CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(newTag)); } }
void CGUIWindowPVRGuideBase::OnInputDone() { const int iChannelNumber = GetChannelNumber(); if (iChannelNumber >= 0) { for (const CFileItemPtr event : m_vecItems->GetList()) { const CPVREpgInfoTagPtr tag(event->GetEPGInfoTag()); if (tag->HasChannel() && tag->ChannelNumber() == iChannelNumber) { CGUIEPGGridContainer* epgGridContainer = GetGridControl(); if (epgGridContainer) { epgGridContainer->SetChannel(tag->Channel()); return; } } } } }
bool CPVREpgSearchFilter::MatchChannelGroup(const CPVREpgInfoTagPtr &tag) const { bool bReturn(true); if (m_iChannelGroup != EPG_SEARCH_UNSET && CServiceBroker::GetPVRManager().IsStarted()) { CPVRChannelGroupPtr group = CServiceBroker::GetPVRManager().ChannelGroups()->GetByIdFromAll(m_iChannelGroup); bReturn = (group && group->IsGroupMember(tag->Channel())); } return bReturn; }
CPVRRecordingPtr CPVRRecordings::GetRecordingForEpgTag(const CPVREpgInfoTagPtr &epgTag) const { CSingleLock lock(m_critSection); for (const auto recording : m_recordings) { if (recording.second->IsDeleted()) continue; unsigned int iEpgEvent = recording.second->BroadcastUid(); if (iEpgEvent != EPG_TAG_INVALID_UID) { if (iEpgEvent == epgTag->UniqueBroadcastID()) { // uid matches. perfect. return recording.second; } } else { // uid is optional, so check other relevant data. // note: don't use recording.second->Channel() for comparing channels here as this can lead // to deadlocks. compare client ids and channel ids instead, this has the same effect. if (epgTag->Channel() && recording.second->ClientID() == epgTag->Channel()->ClientID() && recording.second->ChannelUid() == epgTag->Channel()->UniqueID() && recording.second->RecordingTimeAsUTC() <= epgTag->StartAsUTC() && recording.second->EndTimeAsUTC() >= epgTag->EndAsUTC()) return recording.second; } } return CPVRRecordingPtr(); }
void CPVRRecordings::UpdateFromClient(const CPVRRecordingPtr &tag) { CSingleLock lock(m_critSection); if (tag->IsDeleted()) { if (tag->IsRadio()) m_bDeletedRadioRecordings = true; else m_bDeletedTVRecordings = true; } CPVRRecordingPtr newTag = GetById(tag->m_iClientId, tag->m_strRecordingId); if (newTag) { newTag->Update(*tag); } else { newTag = CPVRRecordingPtr(new CPVRRecording); newTag->Update(*tag); if (newTag->BroadcastUid() != EPG_TAG_INVALID_UID) { const CPVRChannelPtr channel(newTag->Channel()); if (channel) { const CPVREpgInfoTagPtr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(channel, newTag->BroadcastUid()); if (epgTag) epgTag->SetRecording(newTag); } } newTag->m_iRecordingId = ++m_iLastId; m_recordings.insert(std::make_pair(CPVRRecordingUid(newTag->m_iClientId, newTag->m_strRecordingId), newTag)); if (newTag->IsRadio()) ++m_iRadioRecordings; else ++m_iTVRecordings; } }
/*! * @brief Copy over timer info from xbmcTimer to addonTimer. * @param xbmcTimer The timer on XBMC's side. * @param addonTimer The timer on the addon's side. */ void CPVRClient::WriteClientTimerInfo(const CPVRTimerInfoTag &xbmcTimer, PVR_TIMER &addonTimer) { time_t start, end, firstDay; xbmcTimer.StartAsUTC().GetAsTime(start); xbmcTimer.EndAsUTC().GetAsTime(end); xbmcTimer.FirstDayAsUTC().GetAsTime(firstDay); CPVREpgInfoTagPtr epgTag = xbmcTimer.GetEpgInfoTag(); memset(&addonTimer, 0, sizeof(addonTimer)); addonTimer.iClientIndex = xbmcTimer.m_iClientIndex; addonTimer.iParentClientIndex = xbmcTimer.m_iParentClientIndex; addonTimer.state = xbmcTimer.m_state; addonTimer.iTimerType = xbmcTimer.GetTimerType() ? xbmcTimer.GetTimerType()->GetTypeId() : PVR_TIMER_TYPE_NONE; addonTimer.iClientChannelUid = xbmcTimer.m_iClientChannelUid; strncpy(addonTimer.strTitle, xbmcTimer.m_strTitle.c_str(), sizeof(addonTimer.strTitle) - 1); strncpy(addonTimer.strEpgSearchString, xbmcTimer.m_strEpgSearchString.c_str(), sizeof(addonTimer.strEpgSearchString) - 1); addonTimer.bFullTextEpgSearch = xbmcTimer.m_bFullTextEpgSearch; strncpy(addonTimer.strDirectory, xbmcTimer.m_strDirectory.c_str(), sizeof(addonTimer.strDirectory) - 1); addonTimer.iPriority = xbmcTimer.m_iPriority; addonTimer.iLifetime = xbmcTimer.m_iLifetime; addonTimer.iMaxRecordings = xbmcTimer.m_iMaxRecordings; addonTimer.iPreventDuplicateEpisodes = xbmcTimer.m_iPreventDupEpisodes; addonTimer.iRecordingGroup = xbmcTimer.m_iRecordingGroup; addonTimer.iWeekdays = xbmcTimer.m_iWeekdays; addonTimer.startTime = start - g_advancedSettings.m_iPVRTimeCorrection; addonTimer.endTime = end - g_advancedSettings.m_iPVRTimeCorrection; addonTimer.bStartAnyTime = xbmcTimer.m_bStartAnyTime; addonTimer.bEndAnyTime = xbmcTimer.m_bEndAnyTime; addonTimer.firstDay = firstDay - g_advancedSettings.m_iPVRTimeCorrection; addonTimer.iEpgUid = epgTag ? epgTag->UniqueBroadcastID() : PVR_TIMER_NO_EPG_UID; strncpy(addonTimer.strSummary, xbmcTimer.m_strSummary.c_str(), sizeof(addonTimer.strSummary) - 1); addonTimer.iMarginStart = xbmcTimer.m_iMarginStart; addonTimer.iMarginEnd = xbmcTimer.m_iMarginEnd; addonTimer.iGenreType = epgTag ? epgTag->GenreType() : 0; addonTimer.iGenreSubType = epgTag ? epgTag->GenreSubType() : 0; }
bool CPVREpgSearchFilter::FilterEntry(const CPVREpgInfoTagPtr &tag) const { return (MatchGenre(tag) && MatchBroadcastId(tag) && MatchDuration(tag) && MatchStartAndEndTimes(tag) && MatchSearchTerm(tag) && MatchTimers(tag) && MatchRecordings(tag)) && (!tag->HasChannel() || (MatchChannelType(tag) && MatchChannelNumber(tag) && MatchChannelGroup(tag) && MatchFreeToAir(tag))); }
bool CPVREpgSearchFilter::MatchChannelNumber(const CPVREpgInfoTagPtr &tag) const { bool bReturn(true); if (m_channelNumber.IsValid() && CServiceBroker::GetPVRManager().IsStarted()) { CPVRChannelGroupPtr group = (m_iChannelGroup != EPG_SEARCH_UNSET) ? CServiceBroker::GetPVRManager().ChannelGroups()->GetByIdFromAll(m_iChannelGroup) : CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllTV(); if (!group) group = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllTV(); bReturn = (m_channelNumber == group->GetChannelNumber(tag->Channel())); } return bReturn; }
int CGUIEPGGridContainerModel::GetFirstEventBlock(const CPVREpgInfoTagPtr &event) const { const CDateTime eventStart = event->StartAsUTC(); int diff; if (m_gridStart == eventStart) return 0; // block is at grid start else if (m_gridStart > eventStart) diff = -1 * (m_gridStart - eventStart).GetSecondsTotal(); else diff = (eventStart - m_gridStart).GetSecondsTotal(); // First block of a tag is always the block calculated using event's start time, rounded up. // Refer to CGUIEPGGridContainerModel::Refresh, where the model is created, for details! float fBlockIndex = diff / 60.0f / MINSPERBLOCK; return std::ceil(fBlockIndex); }
void CGUIEPGGridContainerModel::FindChannelAndBlockIndex(int channelUid, unsigned int broadcastUid, int eventOffset, int &newChannelIndex, int &newBlockIndex) const { const CDateTimeSpan blockDuration(0, 0, MINSPERBLOCK, 0); newChannelIndex = INVALID_INDEX; newBlockIndex = INVALID_INDEX; // find the channel int iCurrentChannel = 0; for (const auto& channel : m_channelItems) { if (channel->GetPVRChannelInfoTag()->UniqueID() == channelUid) { newChannelIndex = iCurrentChannel; break; } iCurrentChannel++; } if (newChannelIndex != INVALID_INDEX) { // find the block CDateTime gridCursor(m_gridStart); //reset cursor for new channel unsigned long progIdx = m_epgItemsPtr[newChannelIndex].start; unsigned long lastIdx = m_epgItemsPtr[newChannelIndex].stop; int iEpgId = m_programmeItems[progIdx]->GetEPGInfoTag()->EpgID(); CPVREpgInfoTagPtr tag; for (int block = 0; block < m_blocks; ++block) { while (progIdx <= lastIdx) { tag = m_programmeItems[progIdx]->GetEPGInfoTag(); if (tag->EpgID() != iEpgId || gridCursor < tag->StartAsUTC() || m_gridEnd <= tag->StartAsUTC()) break; // next block if (gridCursor < tag->EndAsUTC()) { if (broadcastUid > 0 && tag->UniqueBroadcastID() == broadcastUid) { newBlockIndex = block + eventOffset; return; // done. } break; // next block } progIdx++; } gridCursor += blockDuration; } } }
int CGUIEPGGridContainerModel::GetLastEventBlock(const CPVREpgInfoTagPtr &event) const { // Last block of a tag is always the block calculated using event's end time, not rounded up. // Refer to CGUIEPGGridContainerModel::Refresh, where the model is created, for details! return GetBlock(event->EndAsUTC()); }
void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr<CFileItemList> &items, const CDateTime &gridStart, const CDateTime &gridEnd, int iRulerUnit, int iBlocksPerPage, float fBlockSize) { if (!m_channelItems.empty()) { CLog::LogF(LOGERROR, "Already initialized!"); return; } //////////////////////////////////////////////////////////////////////// // Create programme & channel items m_programmeItems.reserve(items->Size()); CFileItemPtr fileItem; int iLastChannelID = -1; ItemsPtr itemsPointer; itemsPointer.start = 0; CPVRChannelPtr channel; int j = 0; for (int i = 0; i < items->Size(); ++i) { fileItem = items->Get(i); if (!fileItem->HasEPGInfoTag() || !fileItem->GetEPGInfoTag()->HasChannel()) continue; m_programmeItems.emplace_back(fileItem); channel = fileItem->GetEPGInfoTag()->Channel(); if (!channel) continue; int iCurrentChannelID = channel->ChannelID(); if (iCurrentChannelID != iLastChannelID) { if (j > 0) { itemsPointer.stop = j - 1; m_epgItemsPtr.emplace_back(itemsPointer); itemsPointer.start = j; } iLastChannelID = iCurrentChannelID; m_channelItems.emplace_back(CFileItemPtr(new CFileItem(channel))); } ++j; } if (!m_programmeItems.empty()) { itemsPointer.stop = m_programmeItems.size() - 1; m_epgItemsPtr.emplace_back(itemsPointer); } /* check for invalid start and end time */ if (gridStart >= gridEnd) { // default to start "now minus GRID_START_PADDING minutes" and end "start plus one page". m_gridStart = CDateTime::GetUTCDateTime() - CDateTimeSpan(0, 0, GetGridStartPadding(), 0); m_gridEnd = m_gridStart + CDateTimeSpan(0, 0, iBlocksPerPage * MINSPERBLOCK, 0); } else if (gridStart > (CDateTime::GetUTCDateTime() - CDateTimeSpan(0, 0, GetGridStartPadding(), 0))) { // adjust to start "now minus GRID_START_PADDING minutes". m_gridStart = CDateTime::GetUTCDateTime() - CDateTimeSpan(0, 0, GetGridStartPadding(), 0); m_gridEnd = gridEnd; } else { m_gridStart = gridStart; m_gridEnd = gridEnd; } // roundup m_gridStart = CDateTime(m_gridStart.GetYear(), m_gridStart.GetMonth(), m_gridStart.GetDay(), m_gridStart.GetHour(), m_gridStart.GetMinute() >= 30 ? 30 : 0, 0); m_gridEnd = CDateTime(m_gridEnd.GetYear(), m_gridEnd.GetMonth(), m_gridEnd.GetDay(), m_gridEnd.GetHour(), m_gridEnd.GetMinute() >= 30 ? 30 : 0, 0); //////////////////////////////////////////////////////////////////////// // Create ruler items CDateTime ruler; ruler.SetFromUTCDateTime(m_gridStart); CDateTime rulerEnd; rulerEnd.SetFromUTCDateTime(m_gridEnd); CFileItemPtr rulerItem(new CFileItem(ruler.GetAsLocalizedDate(true))); rulerItem->SetProperty("DateLabel", true); m_rulerItems.emplace_back(rulerItem); const CDateTimeSpan unit(0, 0, iRulerUnit * MINSPERBLOCK, 0); for (; ruler < rulerEnd; ruler += unit) { rulerItem.reset(new CFileItem(ruler.GetAsLocalizedTime("", false))); rulerItem->SetLabel2(ruler.GetAsLocalizedDate(true)); m_rulerItems.emplace_back(rulerItem); } FreeItemsMemory(); //////////////////////////////////////////////////////////////////////// // Create epg grid const CDateTimeSpan blockDuration(0, 0, MINSPERBLOCK, 0); const CDateTimeSpan gridDuration(m_gridEnd - m_gridStart); m_blocks = (gridDuration.GetDays() * 24 * 60 + gridDuration.GetHours() * 60 + gridDuration.GetMinutes()) / MINSPERBLOCK; if (m_blocks >= MAXBLOCKS) m_blocks = MAXBLOCKS; else if (m_blocks < iBlocksPerPage) m_blocks = iBlocksPerPage; m_gridIndex.reserve(m_channelItems.size()); const std::vector<GridItem> blocks(m_blocks); for (size_t channel = 0; channel < m_channelItems.size(); ++channel) { m_gridIndex.emplace_back(blocks); CDateTime gridCursor(m_gridStart); //reset cursor for new channel unsigned long progIdx = m_epgItemsPtr[channel].start; unsigned long lastIdx = m_epgItemsPtr[channel].stop; int iEpgId = m_programmeItems[progIdx]->GetEPGInfoTag()->EpgID(); int itemSize = 1; // size of the programme in blocks int savedBlock = 0; CFileItemPtr item; CPVREpgInfoTagPtr tag; for (int block = 0; block < m_blocks; ++block) { while (progIdx <= lastIdx) { item = m_programmeItems[progIdx]; tag = item->GetEPGInfoTag(); // Note: Start block of an event is start-time-based calculated block + 1, // unless start times matches exactly the begin of a block. if (tag->EpgID() != iEpgId || gridCursor < tag->StartAsUTC() || m_gridEnd <= tag->StartAsUTC()) break; if (gridCursor < tag->EndAsUTC()) { m_gridIndex[channel][block].item = item; m_gridIndex[channel][block].progIndex = progIdx; break; } progIdx++; } gridCursor += blockDuration; if (block == 0) continue; const CFileItemPtr prevItem(m_gridIndex[channel][block - 1].item); const CFileItemPtr currItem(m_gridIndex[channel][block].item); if (block == m_blocks - 1 || prevItem != currItem) { // special handling for last block. int blockDelta = -1; int sizeDelta = 0; if (block == m_blocks - 1 && prevItem == currItem) { itemSize++; blockDelta = 0; sizeDelta = 1; } if (prevItem) { m_gridIndex[channel][savedBlock].item->SetProperty("GenreType", prevItem->GetEPGInfoTag()->GenreType()); } else { CPVREpgInfoTagPtr gapTag(CPVREpgInfoTag::CreateDefaultTag()); gapTag->SetChannel(m_channelItems[channel]->GetPVRChannelInfoTag()); CFileItemPtr gapItem(new CFileItem(gapTag)); for (int i = block + blockDelta; i >= block - itemSize + sizeDelta; --i) { m_gridIndex[channel][i].item = gapItem; } } float fItemWidth = itemSize * fBlockSize; m_gridIndex[channel][savedBlock].originWidth = fItemWidth; m_gridIndex[channel][savedBlock].width = fItemWidth; itemSize = 1; savedBlock = block; // special handling for last block. if (block == m_blocks - 1 && prevItem != currItem) { if (currItem) { m_gridIndex[channel][savedBlock].item->SetProperty("GenreType", currItem->GetEPGInfoTag()->GenreType()); } else { CPVREpgInfoTagPtr gapTag(CPVREpgInfoTag::CreateDefaultTag()); gapTag->SetChannel(m_channelItems[channel]->GetPVRChannelInfoTag()); CFileItemPtr gapItem(new CFileItem(gapTag)); m_gridIndex[channel][block].item = gapItem; } m_gridIndex[channel][savedBlock].originWidth = fBlockSize; // size always 1 block here m_gridIndex[channel][savedBlock].width = fBlockSize; } } else { itemSize++; } } } }
bool CPVREpg::UpdateEntry(const CPVREpgInfoTagPtr &tag, bool bUpdateDatabase) { CPVREpgInfoTagPtr infoTag; { CSingleLock lock(m_critSection); std::map<CDateTime, CPVREpgInfoTagPtr>::iterator it = m_tags.find(tag->StartAsUTC()); bool bNewTag(false); if (it != m_tags.end()) { infoTag = it->second; } else { infoTag.reset(new CPVREpgInfoTag(this, m_pvrChannel, m_strName, m_pvrChannel ? m_pvrChannel->IconPath() : "")); infoTag->SetUniqueBroadcastID(tag->UniqueBroadcastID()); m_tags.insert(std::make_pair(tag->StartAsUTC(), infoTag)); bNewTag = true; } infoTag->Update(*tag, bNewTag); infoTag->SetEpg(this); infoTag->SetChannel(m_pvrChannel); if (bUpdateDatabase) m_changedTags.insert(std::make_pair(infoTag->UniqueBroadcastID(), infoTag)); } infoTag->SetTimer(CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(infoTag)); infoTag->SetRecording(CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(infoTag)); return true; }
bool CPVRGUIInfo::GetPVRLabel(const CFileItem *item, const CGUIInfo &info, std::string &strValue) const { CSingleLock lock(m_critSection); switch (info.m_info) { case PVR_EPG_EVENT_ICON: { const CPVREpgInfoTagPtr epgTag = (item->IsPVRChannel() || item->IsEPG()) ? CPVRItem(item).GetEpgInfoTag() : nullptr; if (epgTag) { strValue = epgTag->Icon(); } return true; } case PVR_EPG_EVENT_DURATION: { const CPVREpgInfoTagPtr 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 CPVREpgInfoTagPtr 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 CPVREpgInfoTagPtr 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 CPVREpgInfoTagPtr 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: strValue = m_timesInfo.GetEpgEventSeekTime(g_application.GetAppPlayer().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_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 = CServiceBroker::GetPVRManager().GUIActions()->GetChannelNumberInputHandler().GetChannelNumberLabel(); return true; } return false; }
bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message) { bool bReturn = false; switch (message.GetMessage()) { case GUI_MSG_CLICKED: { if (message.GetSenderId() == m_viewControl.GetCurrentControl()) { int iItem = m_viewControl.GetSelectedItem(); if (iItem >= 0 && iItem < m_vecItems->Size()) { CFileItemPtr pItem = m_vecItems->Get(iItem); /* process actions */ switch (message.GetParam1()) { case ACTION_SELECT_ITEM: case ACTION_MOUSE_LEFT_CLICK: switch(CServiceBroker::GetSettings().GetInt(CSettings::SETTING_EPG_SELECTACTION)) { case EPG_SELECT_ACTION_CONTEXT_MENU: OnPopupMenu(iItem); bReturn = true; break; case EPG_SELECT_ACTION_SWITCH: CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(pItem, true); bReturn = true; break; case EPG_SELECT_ACTION_PLAY_RECORDING: CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(pItem, true); bReturn = true; break; case EPG_SELECT_ACTION_INFO: CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(pItem); bReturn = true; break; case EPG_SELECT_ACTION_RECORD: CServiceBroker::GetPVRManager().GUIActions()->ToggleTimer(pItem); bReturn = true; break; case EPG_SELECT_ACTION_SMART_SELECT: { const CPVREpgInfoTagPtr tag(pItem->GetEPGInfoTag()); if (tag) { const CDateTime start(tag->StartAsUTC()); const CDateTime end(tag->EndAsUTC()); const CDateTime now(CDateTime::GetUTCDateTime()); if (start <= now && now <= end) { // current event CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(pItem, true); } else if (now < start) { // future event if (tag->HasTimer()) CServiceBroker::GetPVRManager().GUIActions()->EditTimer(pItem); else CServiceBroker::GetPVRManager().GUIActions()->AddTimer(pItem, false); } else { // past event if (tag->HasRecording()) CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(pItem, true); else if (tag->IsPlayable()) CServiceBroker::GetPVRManager().GUIActions()->PlayEpgTag(pItem); else CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(pItem); } bReturn = true; } break; } } break; case ACTION_SHOW_INFO: CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(pItem); bReturn = true; break; case ACTION_PLAY: CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(pItem, true); bReturn = true; break; case ACTION_RECORD: CServiceBroker::GetPVRManager().GUIActions()->ToggleTimer(pItem); bReturn = true; break; case ACTION_PVR_SHOW_TIMER_RULE: CServiceBroker::GetPVRManager().GUIActions()->AddTimerRule(pItem, true); bReturn = true; break; case ACTION_CONTEXT_MENU: case ACTION_MOUSE_RIGHT_CLICK: OnPopupMenu(iItem); bReturn = true; break; } } else if (iItem == -1) { /* process actions */ switch (message.GetParam1()) { case ACTION_SELECT_ITEM: case ACTION_MOUSE_LEFT_CLICK: case ACTION_PLAY: { // EPG "gap" selected => switch to associated channel. CGUIEPGGridContainer *epgGridContainer = GetGridControl(); if (epgGridContainer) { const CFileItemPtr item(epgGridContainer->GetSelectedChannelItem()); if (item) { CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(item, true); bReturn = true; } } break; } } } } else if (message.GetSenderId() == CONTROL_BTNVIEWASICONS) { // let's set the view mode first before update CGUIWindowPVRBase::OnMessage(message); Refresh(true); bReturn = true; } break; } case GUI_MSG_CHANGE_VIEW_MODE: { // let's set the view mode first before update CGUIWindowPVRBase::OnMessage(message); // force data update for the new view control { CSingleLock lock(m_critSection); m_bRefreshTimelineItems = true; } Init(); Refresh(true); bReturn = true; break; } case GUI_MSG_REFRESH_LIST: switch(message.GetParam1()) { case ObservableMessageChannelGroupsLoaded: { // late init InitChannelGroup(); Init(); break; } case ObservableMessageChannelGroupReset: case ObservableMessageChannelGroup: case ObservableMessageEpg: case ObservableMessageEpgContainer: { Refresh(true); break; } case ObservableMessageTimersReset: case ObservableMessageTimers: { SetInvalid(); break; } } break; } return bReturn || CGUIWindowPVRBase::OnMessage(message); }