2 * Copyright (C) 2012-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "guilib/LocalizeStrings.h"
22 #include "settings/AdvancedSettings.h"
23 #include "settings/GUISettings.h"
24 #include "threads/SingleLock.h"
25 #include "utils/log.h"
26 #include "utils/TimeUtils.h"
28 #include "EpgDatabase.h"
29 #include "EpgContainer.h"
30 #include "pvr/PVRManager.h"
31 #include "pvr/addons/PVRClients.h"
32 #include "pvr/channels/PVRChannelGroupsContainer.h"
33 #include "utils/StringUtils.h"
35 #include "../addons/include/xbmc_epg_types.h"
41 CEpg::CEpg(int iEpgID, const CStdString &strName /* = "" */, const CStdString &strScraperName /* = "" */, bool bLoadedFromDb /* = false */) :
42 m_bChanged(!bLoadedFromDb),
43 m_bTagsChanged(false),
45 m_bUpdatePending(false),
48 m_strScraperName(strScraperName),
49 m_bUpdateLastScanTime(false)
55 CEpg::CEpg(CPVRChannelPtr channel, bool bLoadedFromDb /* = false */) :
56 m_bChanged(!bLoadedFromDb),
57 m_bTagsChanged(false),
59 m_bUpdatePending(false),
60 m_iEpgID(channel->EpgID()),
61 m_strName(channel->ChannelName()),
62 m_strScraperName(channel->EPGScraper()),
63 m_pvrChannel(channel),
64 m_bUpdateLastScanTime(false)
70 m_bTagsChanged(false),
72 m_bUpdatePending(false),
74 m_bUpdateLastScanTime(false)
85 CEpg &CEpg::operator =(const CEpg &right)
87 m_bChanged = right.m_bChanged;
88 m_bTagsChanged = right.m_bTagsChanged;
89 m_bLoaded = right.m_bLoaded;
90 m_bUpdatePending = right.m_bUpdatePending;
91 m_iEpgID = right.m_iEpgID;
92 m_strName = right.m_strName;
93 m_strScraperName = right.m_strScraperName;
94 m_nowActiveStart = right.m_nowActiveStart;
95 m_lastScanTime = right.m_lastScanTime;
96 m_pvrChannel = right.m_pvrChannel;
98 for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = right.m_tags.begin(); it != right.m_tags.end(); it++)
99 m_tags.insert(make_pair(it->first, new CEpgInfoTag(*it->second)));
104 /** @name Public methods */
107 void CEpg::SetName(const CStdString &strName)
109 CSingleLock lock(m_critSection);
111 if (!m_strName.Equals(strName))
118 void CEpg::SetScraperName(const CStdString &strScraperName)
120 CSingleLock lock(m_critSection);
122 if (!m_strScraperName.Equals(strScraperName))
125 m_strScraperName = strScraperName;
129 void CEpg::SetUpdatePending(bool bUpdatePending /* = true */)
132 CSingleLock lock(m_critSection);
133 m_bUpdatePending = bUpdatePending;
137 g_EpgContainer.SetHasPendingUpdates(true);
140 void CEpg::ForceUpdate(void)
145 bool CEpg::HasValidEntries(void) const
147 CSingleLock lock(m_critSection);
149 return (m_iEpgID > 0 && /* valid EPG ID */
150 m_tags.size() > 0 && /* contains at least 1 tag */
151 m_tags.rbegin()->second->EndAsUTC() >= CDateTime::GetCurrentDateTime().GetAsUTCDateTime()); /* the last end time hasn't passed yet */
154 void CEpg::Clear(void)
156 CSingleLock lock(m_critSection);
160 void CEpg::Cleanup(void)
162 CDateTime cleanupTime = CDateTime::GetCurrentDateTime().GetAsUTCDateTime() -
163 CDateTimeSpan(0, g_advancedSettings.m_iEpgLingerTime / 60, g_advancedSettings.m_iEpgLingerTime % 60, 0);
164 Cleanup(cleanupTime);
167 void CEpg::Cleanup(const CDateTime &Time)
169 CSingleLock lock(m_critSection);
170 for (map<CDateTime, CEpgInfoTagPtr>::iterator it = m_tags.begin(); it != m_tags.end(); it != m_tags.end() ? it++ : it)
172 if (it->second->EndAsUTC() < Time)
174 if (m_nowActiveStart == it->first)
175 m_nowActiveStart.SetValid(false);
177 it->second->ClearTimer();
183 bool CEpg::InfoTagNow(CEpgInfoTag &tag, bool bUpdateIfNeeded /* = true */)
185 CSingleLock lock(m_critSection);
186 if (m_nowActiveStart.IsValid())
188 map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.find(m_nowActiveStart);
189 if (it != m_tags.end() && it->second->IsActive())
198 CDateTime lastActiveTag;
200 /* one of the first items will always match if the list is sorted */
201 for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.begin(); it != m_tags.end(); it++)
203 if (it->second->IsActive())
205 m_nowActiveStart = it->first;
209 else if (it->second->WasActive())
210 lastActiveTag = it->first;
213 /* there might be a gap between the last and next event. just return the last if found */
214 map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.find(lastActiveTag);
215 if (it != m_tags.end())
225 bool CEpg::InfoTagNext(CEpgInfoTag &tag)
228 if (InfoTagNow(nowTag))
230 CSingleLock lock(m_critSection);
231 map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.find(nowTag.StartAsUTC());
232 if (it != m_tags.end() && ++it != m_tags.end())
240 /* return the first event that is in the future */
241 for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.begin(); it != m_tags.end(); it++)
243 if (it->second->InTheFuture())
254 bool CEpg::CheckPlayingEvent(void)
257 CEpgInfoTag previousTag, newTag;
258 bool bGotPreviousTag = InfoTagNow(previousTag, false);
259 bool bGotCurrentTag = InfoTagNow(newTag);
261 bool bTagChanged = bGotCurrentTag && (!bGotPreviousTag || previousTag != newTag);
262 bool bTagRemoved = !bGotCurrentTag && bGotPreviousTag;
263 if (bTagChanged || bTagRemoved)
265 NotifyObservers(ObservableMessageEpgActiveItem);
272 CEpgInfoTagPtr CEpg::GetTag(const CDateTime &StartTime) const
274 CSingleLock lock(m_critSection);
275 map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.find(StartTime);
276 if (it != m_tags.end())
281 CEpgInfoTagPtr empty;
285 CEpgInfoTagPtr CEpg::GetTagBetween(const CDateTime &beginTime, const CDateTime &endTime) const
287 CSingleLock lock(m_critSection);
288 for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.begin(); it != m_tags.end(); it++)
290 if (it->second->StartAsUTC() >= beginTime && it->second->EndAsUTC() <= endTime)
294 CEpgInfoTagPtr retVal;
298 CEpgInfoTagPtr CEpg::GetTagAround(const CDateTime &time) const
300 CSingleLock lock(m_critSection);
301 for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.begin(); it != m_tags.end(); it++)
303 if ((it->second->StartAsUTC() <= time) && (it->second->EndAsUTC() >= time))
307 CEpgInfoTagPtr retVal;
311 void CEpg::AddEntry(const CEpgInfoTag &tag)
313 CEpgInfoTagPtr newTag;
314 CSingleLock lock(m_critSection);
315 map<CDateTime, CEpgInfoTagPtr>::iterator itr = m_tags.find(tag.StartAsUTC());
316 if (itr != m_tags.end())
317 newTag = itr->second;
320 newTag = CEpgInfoTagPtr(new CEpgInfoTag(this, m_pvrChannel, m_strName, m_pvrChannel ? m_pvrChannel->IconPath() : StringUtils::EmptyString));
321 m_tags.insert(make_pair(tag.StartAsUTC(), newTag));
327 newTag->SetPVRChannel(m_pvrChannel);
328 newTag->m_epg = this;
329 newTag->m_bChanged = false;
333 bool CEpg::UpdateEntry(const CEpgInfoTag &tag, bool bUpdateDatabase /* = false */, bool bSort /* = true */)
335 CEpgInfoTagPtr infoTag;
336 CSingleLock lock(m_critSection);
337 map<CDateTime, CEpgInfoTagPtr>::iterator it = m_tags.find(tag.StartAsUTC());
339 if (it != m_tags.end())
341 infoTag = it->second;
345 /* create a new tag if no tag with this ID exists */
346 infoTag = CEpgInfoTagPtr(new CEpgInfoTag(this, m_pvrChannel, m_strName, m_pvrChannel ? m_pvrChannel->IconPath() : StringUtils::EmptyString));
347 infoTag->SetUniqueBroadcastID(tag.UniqueBroadcastID());
348 m_tags.insert(make_pair(tag.StartAsUTC(), infoTag));
352 infoTag->Update(tag, bNewTag);
353 infoTag->m_epg = this;
354 infoTag->m_pvrChannel = m_pvrChannel;
357 m_changedTags.insert(make_pair<int, CEpgInfoTagPtr>(infoTag->UniqueBroadcastID(), infoTag));
362 bool CEpg::Load(void)
365 CEpgDatabase *database = g_EpgContainer.GetDatabase();
367 if (!database || !database->IsOpen())
369 CLog::Log(LOGERROR, "EPG - %s - could not open the database", __FUNCTION__);
373 CSingleLock lock(m_critSection);
374 int iEntriesLoaded = database->Get(*this);
375 if (iEntriesLoaded <= 0)
377 CLog::Log(LOGDEBUG, "EPG - %s - no database entries found for table '%s'.", __FUNCTION__, m_strName.c_str());
381 m_lastScanTime = GetLastScanTime();
383 CLog::Log(LOGDEBUG, "EPG - %s - %d entries loaded for table '%s'.", __FUNCTION__, (int) m_tags.size(), m_strName.c_str());
393 bool CEpg::UpdateEntries(const CEpg &epg, bool bStoreInDb /* = true */)
395 CSingleLock lock(m_critSection);
397 CLog::Log(LOGDEBUG, "EPG - %s - %zu entries in memory before merging", __FUNCTION__, m_tags.size());
400 for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = epg.m_tags.begin(); it != epg.m_tags.end(); it++)
401 UpdateEntry(*it->second, bStoreInDb, false);
404 CLog::Log(LOGDEBUG, "EPG - %s - %zu entries in memory after merging and before fixing", __FUNCTION__, m_tags.size());
406 FixOverlappingEvents(bStoreInDb);
409 CLog::Log(LOGDEBUG, "EPG - %s - %zu entries in memory after fixing", __FUNCTION__, m_tags.size());
411 /* update the last scan time of this table */
412 m_lastScanTime = CDateTime::GetCurrentDateTime().GetAsUTCDateTime();
413 m_bUpdateLastScanTime = true;
415 NotifyObservers(ObservableMessageEpg);
420 CDateTime CEpg::GetLastScanTime(void)
422 CDateTime lastScanTime;
424 CSingleLock lock(m_critSection);
426 if (!m_lastScanTime.IsValid())
428 if (!g_guiSettings.GetBool("epg.ignoredbforclient"))
430 CEpgDatabase *database = g_EpgContainer.GetDatabase();
431 CDateTime dtReturn; dtReturn.SetValid(false);
433 if (database && database->IsOpen())
434 database->GetLastEpgScanTime(m_iEpgID, &m_lastScanTime);
437 if (!m_lastScanTime.IsValid())
439 m_lastScanTime.SetDateTime(0, 0, 0, 0, 0, 0);
440 m_lastScanTime.SetValid(true);
443 lastScanTime = m_lastScanTime;
446 return m_lastScanTime;
449 bool CEpg::Update(const time_t start, const time_t end, int iUpdateTime, bool bForceUpdate /* = false */)
451 bool bGrabSuccess(true);
454 /* load the entries from the db first */
455 if (!m_bLoaded && !g_EpgContainer.IgnoreDB())
458 /* clean up if needed */
462 /* get the last update time from the database */
463 CDateTime lastScanTime = GetLastScanTime();
465 /* enforce advanced settings update interval override for TV Channels with no EPG data */
466 if (m_tags.empty() && !bUpdate && ChannelID() > 0 && !Channel()->IsRadio())
467 iUpdateTime = g_advancedSettings.m_iEpgUpdateEmptyTagsInterval;
471 /* check if we have to update */
473 time_t iLastUpdate = 0;
474 CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow);
475 lastScanTime.GetAsTime(iLastUpdate);
476 bUpdate = (iNow > iLastUpdate + iUpdateTime);
482 bGrabSuccess = LoadFromClients(start, end);
486 CPVRChannelPtr channel;
487 if (g_PVRManager.GetCurrentChannel(channel) &&
488 channel->EpgID() == m_iEpgID)
489 g_PVRManager.ResetPlayingTag();
493 CLog::Log(LOGERROR, "EPG - %s - failed to update table '%s'", __FUNCTION__, Name().c_str());
495 CSingleLock lock(m_critSection);
496 m_bUpdatePending = false;
501 int CEpg::Get(CFileItemList &results) const
503 int iInitialSize = results.Size();
505 CSingleLock lock(m_critSection);
507 for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.begin(); it != m_tags.end(); it++)
508 results.Add(CFileItemPtr(new CFileItem(*it->second)));
510 return results.Size() - iInitialSize;
513 int CEpg::Get(CFileItemList &results, const EpgSearchFilter &filter) const
515 int iInitialSize = results.Size();
517 if (!HasValidEntries())
520 CSingleLock lock(m_critSection);
522 for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.begin(); it != m_tags.end(); it++)
524 if (filter.FilterEntry(*it->second))
525 results.Add(CFileItemPtr(new CFileItem(*it->second)));
528 return results.Size() - iInitialSize;
531 bool CEpg::Persist(void)
533 if (g_guiSettings.GetBool("epg.ignoredbforclient") || !NeedsSave())
537 CLog::Log(LOGDEBUG, "persist table '%s' (#%d) changed=%d deleted=%d", Name().c_str(), m_iEpgID, m_changedTags.size(), m_deletedTags.size());
540 CEpgDatabase *database = g_EpgContainer.GetDatabase();
541 if (!database || !database->IsOpen())
543 CLog::Log(LOGERROR, "EPG - %s - could not open the database", __FUNCTION__);
548 CSingleLock lock(m_critSection);
549 if (m_iEpgID <= 0 || m_bChanged)
551 int iId = database->Persist(*this, m_iEpgID > 0);
556 for (std::map<int, CEpgInfoTagPtr>::iterator it = m_deletedTags.begin(); it != m_deletedTags.end(); it++)
557 database->Delete(*it->second);
559 for (std::map<int, CEpgInfoTagPtr>::iterator it = m_changedTags.begin(); it != m_changedTags.end(); it++)
560 it->second->Persist(false);
562 if (m_bUpdateLastScanTime)
563 database->PersistLastEpgScanTime(m_iEpgID, true);
565 m_deletedTags.clear();
566 m_changedTags.clear();
568 m_bTagsChanged = false;
569 m_bUpdateLastScanTime = false;
572 return database->CommitInsertQueries();
575 CDateTime CEpg::GetFirstDate(void) const
579 CSingleLock lock(m_critSection);
580 if (m_tags.size() > 0)
581 first = m_tags.begin()->second->StartAsUTC();
586 CDateTime CEpg::GetLastDate(void) const
590 CSingleLock lock(m_critSection);
591 if (m_tags.size() > 0)
592 last = m_tags.rbegin()->second->StartAsUTC();
599 /** @name Private methods */
602 bool CEpg::FixOverlappingEvents(bool bUpdateDb /* = false */)
605 CEpgInfoTagPtr previousTag, currentTag;
607 for (map<CDateTime, CEpgInfoTagPtr>::iterator it = m_tags.begin(); it != m_tags.end(); it != m_tags.end() ? it++ : it)
611 previousTag = it->second;
614 currentTag = it->second;
616 if (previousTag->EndAsUTC() >= currentTag->EndAsUTC())
618 // delete the current tag. it's completely overlapped
620 m_deletedTags.insert(make_pair<int, CEpgInfoTagPtr>(currentTag->UniqueBroadcastID(), currentTag));
622 if (m_nowActiveStart == it->first)
623 m_nowActiveStart.SetValid(false);
625 it->second->ClearTimer();
628 else if (previousTag->EndAsUTC() > currentTag->StartAsUTC())
630 currentTag->SetStartFromUTC(previousTag->EndAsUTC());
632 m_changedTags.insert(make_pair<int, CEpgInfoTagPtr>(currentTag->UniqueBroadcastID(), currentTag));
634 previousTag = it->second;
636 else if (previousTag->EndAsUTC() < currentTag->StartAsUTC())
638 time_t start, end, middle;
639 previousTag->EndAsUTC().GetAsTime(start);
640 currentTag->StartAsUTC().GetAsTime(end);
641 middle = start + ((end - start) / 2);
642 CDateTime newTime(middle);
644 currentTag->SetStartFromUTC(newTime);
645 previousTag->SetEndFromUTC(newTime);
647 if (m_nowActiveStart == it->first)
648 m_nowActiveStart = currentTag->StartAsUTC();
652 m_changedTags.insert(make_pair<int, CEpgInfoTagPtr>(currentTag->UniqueBroadcastID(), currentTag));
653 m_changedTags.insert(make_pair<int, CEpgInfoTagPtr>(previousTag->UniqueBroadcastID(), previousTag));
656 previousTag = it->second;
660 previousTag = it->second;
667 bool CEpg::UpdateFromScraper(time_t start, time_t end)
669 bool bGrabSuccess = false;
670 if (ScraperName() == "client")
672 CPVRChannelPtr channel = Channel();
675 CLog::Log(LOGWARNING, "EPG - %s - channel not found, can't update", __FUNCTION__);
677 else if (!channel->EPGEnabled())
680 CLog::Log(LOGDEBUG, "EPG - %s - EPG updating disabled in the channel configuration", __FUNCTION__);
684 else if (channel->IsHidden())
687 CLog::Log(LOGDEBUG, "EPG - %s - channel '%s' on client '%i' is hidden", __FUNCTION__, channel->ChannelName().c_str(), channel->ClientID());
691 else if (!g_PVRClients->SupportsEPG(channel->ClientID()))
693 CLog::Log(LOGDEBUG, "EPG - %s - the backend for channel '%s' on client '%i' does not support EPGs", __FUNCTION__, channel->ChannelName().c_str(), channel->ClientID());
697 CLog::Log(LOGDEBUG, "EPG - %s - updating EPG for channel '%s' from client '%i'", __FUNCTION__, channel->ChannelName().c_str(), channel->ClientID());
698 bGrabSuccess = (g_PVRClients->GetEPGForChannel(*channel, this, start, end) == PVR_ERROR_NO_ERROR);
701 else if (m_strScraperName.IsEmpty()) /* no grabber defined */
702 CLog::Log(LOGWARNING, "EPG - %s - no EPG scraper defined for table '%s'", __FUNCTION__, m_strName.c_str());
705 CLog::Log(LOGINFO, "EPG - %s - updating EPG table '%s' with scraper '%s'", __FUNCTION__, m_strName.c_str(), m_strScraperName.c_str());
706 CLog::Log(LOGWARNING, "loading the EPG via scraper has not been implemented yet");
707 // TODO: Add Support for Web EPG Scrapers here
715 const CStdString &CEpg::ConvertGenreIdToString(int iID, int iSubID)
717 unsigned int iLabelId = 19499;
720 case EPG_EVENT_CONTENTMASK_MOVIEDRAMA:
721 iLabelId = (iSubID <= 8) ? 19500 + iSubID : 19500;
723 case EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS:
724 iLabelId = (iSubID <= 4) ? 19516 + iSubID : 19516;
726 case EPG_EVENT_CONTENTMASK_SHOW:
727 iLabelId = (iSubID <= 3) ? 19532 + iSubID : 19532;
729 case EPG_EVENT_CONTENTMASK_SPORTS:
730 iLabelId = (iSubID <= 11) ? 19548 + iSubID : 19548;
732 case EPG_EVENT_CONTENTMASK_CHILDRENYOUTH:
733 iLabelId = (iSubID <= 5) ? 19564 + iSubID : 19564;
735 case EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE:
736 iLabelId = (iSubID <= 6) ? 19580 + iSubID : 19580;
738 case EPG_EVENT_CONTENTMASK_ARTSCULTURE:
739 iLabelId = (iSubID <= 11) ? 19596 + iSubID : 19596;
741 case EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS:
742 iLabelId = (iSubID <= 3) ? 19612 + iSubID : 19612;
744 case EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE:
745 iLabelId = (iSubID <= 7) ? 19628 + iSubID : 19628;
747 case EPG_EVENT_CONTENTMASK_LEISUREHOBBIES:
748 iLabelId = (iSubID <= 7) ? 19644 + iSubID : 19644;
750 case EPG_EVENT_CONTENTMASK_SPECIAL:
751 iLabelId = (iSubID <= 3) ? 19660 + iSubID : 19660;
753 case EPG_EVENT_CONTENTMASK_USERDEFINED:
754 iLabelId = (iSubID <= 8) ? 19676 + iSubID : 19676;
760 return g_localizeStrings.Get(iLabelId);
763 bool CEpg::UpdateEntry(const EPG_TAG *data, bool bUpdateDatabase /* = false */)
768 CEpgInfoTag tag(*data);
769 return UpdateEntry(tag, bUpdateDatabase);
772 bool CEpg::IsRadio(void) const
774 CPVRChannelPtr channel = Channel();
775 return channel ? channel->IsRadio() : false;
778 bool CEpg::IsRemovableTag(const CEpgInfoTag &tag) const
780 return !tag.HasTimer();
783 bool CEpg::LoadFromClients(time_t start, time_t end)
786 CPVRChannelPtr channel = Channel();
789 CEpg tmpEpg(channel);
790 if (tmpEpg.UpdateFromScraper(start, end))
791 bReturn = UpdateEntries(tmpEpg, !g_guiSettings.GetBool("epg.ignoredbforclient"));
795 CEpg tmpEpg(m_iEpgID, m_strName, m_strScraperName);
796 if (tmpEpg.UpdateFromScraper(start, end))
797 bReturn = UpdateEntries(tmpEpg, !g_guiSettings.GetBool("epg.ignoredbforclient"));
803 CEpgInfoTagPtr CEpg::GetNextEvent(const CEpgInfoTag& tag) const
805 CSingleLock lock(m_critSection);
806 map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.find(tag.StartAsUTC());
807 if (it != m_tags.end() && ++it != m_tags.end())
810 CEpgInfoTagPtr retVal;
814 CEpgInfoTagPtr CEpg::GetPreviousEvent(const CEpgInfoTag& tag) const
816 CSingleLock lock(m_critSection);
817 map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.find(tag.StartAsUTC());
818 if (it != m_tags.end() && it != m_tags.begin())
824 CEpgInfoTagPtr retVal;
828 CPVRChannelPtr CEpg::Channel(void) const
830 CSingleLock lock(m_critSection);
834 int CEpg::ChannelID(void) const
836 CSingleLock lock(m_critSection);
837 return m_pvrChannel ? m_pvrChannel->ChannelID() : -1;
840 int CEpg::ChannelNumber(void) const
842 CSingleLock lock(m_critSection);
843 return m_pvrChannel ? m_pvrChannel->ChannelNumber() : -1;
846 void CEpg::SetChannel(PVR::CPVRChannelPtr channel)
848 CSingleLock lock(m_critSection);
849 if (m_pvrChannel != channel)
853 SetName(channel->ChannelName());
854 channel->SetEpgID(m_iEpgID);
856 m_pvrChannel = channel;
857 for (map<CDateTime, CEpgInfoTagPtr>::iterator it = m_tags.begin(); it != m_tags.end(); it++)
858 it->second->SetPVRChannel(m_pvrChannel);
862 bool CEpg::HasPVRChannel(void) const
864 CSingleLock lock(m_critSection);
868 bool CEpg::UpdatePending(void) const
870 CSingleLock lock(m_critSection);
871 return m_bUpdatePending;
874 size_t CEpg::Size(void) const
876 CSingleLock lock(m_critSection);
877 return m_tags.size();
880 bool CEpg::NeedsSave(void) const
882 CSingleLock lock(m_critSection);
883 return !m_changedTags.empty() || !m_deletedTags.empty() || m_bChanged;
886 bool CEpg::IsValid(void) const
888 CSingleLock lock(m_critSection);
889 if (ScraperName() == "client")
890 return Channel().get() != NULL;