Esempio n. 1
0
void CAddonCallbacksPVR::PVRTransferTimerEntry(void *addonData, const PVR_HANDLE handle, const PVR_TIMER *timer)
{
  CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
  if (addon == NULL || handle == NULL || timer == NULL)
  {
    CLog::Log(LOGERROR, "CAddonCallbacksPVR - %s - called with a null pointer", __FUNCTION__);
    return;
  }

  CPVRTimers *xbmcTimers = (CPVRTimers*) handle->dataAddress;
  CPVRClient* client     = (CPVRClient*) handle->callerAddress;
  CPVRChannel *channel   = (CPVRChannel *) g_PVRChannelGroups->GetByUniqueID(timer->iClientChannelUid, client->GetClientID());

  if (channel == NULL)
  {
    CLog::Log(LOGERROR, "CAddonCallbacksPVR - %s - cannot find channel %d on client %d",
        __FUNCTION__, timer->iClientChannelUid, client->GetClientID());
    return;
  }

  CPVRTimerInfoTag tag(*timer, channel, client->GetClientID());

  /* transfer this entry to the timers container */
  xbmcTimers->UpdateFromClient(tag);
}
Esempio n. 2
0
void CAddonCallbacksPVR::PVRTransferTimerEntry(void *addonData, const ADDON_HANDLE handle, const PVR_TIMER *timer)
{
  if (!handle)
  {
    CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
    return;
  }

  CPVRClient *client     = GetPVRClient(addonData);
  CPVRTimers *xbmcTimers = static_cast<CPVRTimers *>(handle->dataAddress);
  if (!timer || !client || !xbmcTimers)
  {
    CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
    return;
  }

  CPVRChannelPtr channel = g_PVRChannelGroups->GetByUniqueID(timer->iClientChannelUid, client->GetID());
  if (!channel)
  {
    CLog::Log(LOGERROR, "PVR - %s - cannot find channel %d on client %d", __FUNCTION__, timer->iClientChannelUid, client->GetID());
    return;
  }

  /* transfer this entry to the timers container */
  CPVRTimerInfoTag transferTimer(*timer, channel, client->GetID());
  xbmcTimers->UpdateFromClient(transferTimer);
}
Esempio n. 3
0
void CPVREpgContainer::Clear(bool bClearDb /* = false */)
{
  CSingleLock lock(m_critSection);
  // XXX stop the timers from being updated while clearing tags
  /* remove all pointers to epg tables on timers */
  CPVRTimers *timers = CPVRManager::GetTimers();
  for (unsigned int iTimerPtr = 0; iTimerPtr < timers->size(); iTimerPtr++)
    timers->at(iTimerPtr)->SetEpgInfoTag(NULL);

  CEpgContainer::Clear(bClearDb);
}
Esempio n. 4
0
int CPVREpgContainer::GetEPGSearch(CFileItemList* results, const PVREpgSearchFilter &filter)
{
  CEpgContainer::GetEPGSearch(results, filter);

  /* filter recordings */
  if (filter.m_bIgnorePresentRecordings && CPVRManager::GetRecordings()->size() > 0)
  {
    for (unsigned int iRecordingPtr = 0; iRecordingPtr < CPVRManager::GetRecordings()->size(); iRecordingPtr++)
    {
      for (int iResultPtr = 0; iResultPtr < results->Size(); iResultPtr++)
      {
        const CPVREpgInfoTag *epgentry  = (CPVREpgInfoTag *) results->Get(iResultPtr)->GetEPGInfoTag();
        CPVRRecording *recording = CPVRManager::GetRecordings()->at(iRecordingPtr);
        if (epgentry)
        {
          if (epgentry->Title()       != recording->m_strTitle ||
              epgentry->PlotOutline() != recording->m_strPlotOutline ||
              epgentry->Plot()        != recording->m_strPlot)
            continue;

          results->Remove(iResultPtr);
          iResultPtr--;
        }
      }
    }
  }

  /* filter timers */
  if (filter.m_bIgnorePresentTimers)
  {
    CPVRTimers *timers = CPVRManager::GetTimers();
    for (unsigned int iTimerPtr = 0; iTimerPtr < timers->size(); iTimerPtr++)
    {
      for (int iResultPtr = 0; iResultPtr < results->Size(); iResultPtr++)
      {
        const CPVREpgInfoTag *epgentry = (CPVREpgInfoTag *) results->Get(iResultPtr)->GetEPGInfoTag();
        CPVRTimerInfoTag *timer        = timers->at(iTimerPtr);
        if (epgentry)
        {
          if (epgentry->ChannelTag()->ChannelNumber() != timer->ChannelNumber() ||
              epgentry->Start()                       <  timer->m_StartTime ||
              epgentry->End()                         >  timer->m_StopTime)
            continue;

          results->Remove(iResultPtr);
          iResultPtr--;
        }
      }
    }
  }

  return results->Size();
}
bool CPVRChannelGroupInternal::UpdateTimers(void)
{
  /* update the timers with the new channel numbers */
  CPVRTimers *timers = CPVRManager::GetTimers();
  for (unsigned int ptr = 0; ptr < timers->size(); ptr++)
  {
    CPVRTimerInfoTag *timer = timers->at(ptr);
    const CPVRChannel *tag = GetByClient(timer->Number(), timer->ClientID());
    if (tag)
      timer->SetNumber(tag->ChannelNumber());
  }

  return true;
}
Esempio n. 6
0
bool CPVRChannelGroupInternal::UpdateTimers(void)
{
  CSingleLock lock(m_critSection);

  /* update the timers with the new channel numbers */
  CPVRTimers *timers = g_PVRTimers;
  for (unsigned int ptr = 0; ptr < timers->size(); ptr++)
  {
    CPVRTimerInfoTag *timer = timers->at(ptr);
    const CPVRChannel *tag = GetByClient(timer->m_iClientChannelUid, timer->m_iClientId);
    if (tag)
      timer->m_channel = tag;
  }

  return true;
}
Esempio n. 7
0
JSONRPC_STATUS CPVROperations::GetTimers(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
{
  if (!g_PVRManager.IsStarted())
    return FailedToExecute;

  CPVRTimers* timers = g_PVRTimers;
  if (!timers)
    return FailedToExecute;

  CFileItemList timerList;
  timers->GetAll(timerList);

  HandleFileItemList("timerid", false, "timers", timerList, parameterObject, result, true);

  return OK;
}
Esempio n. 8
0
JSONRPC_STATUS CPVROperations::DeleteTimer(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
{
  if (!g_PVRManager.IsStarted())
    return FailedToExecute;

  CPVRTimers* timers = g_PVRTimers;

  CPVRTimerInfoTagPtr timer = timers->GetById(parameterObject["timerid"].asInteger());
  if (!timer)
    return InvalidParams;

  if (timers->DeleteTimer(timer, timer->IsRecording(), false))
    return ACK;

  return FailedToExecute;
}
Esempio n. 9
0
JSONRPC_STATUS CPVROperations::GetTimerDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
{
  if (!g_PVRManager.IsStarted())
    return FailedToExecute;

  CPVRTimers* timers = g_PVRTimers;
  if (!timers)
    return FailedToExecute;

  CPVRTimerInfoTagPtr timer = timers->GetById((int)parameterObject["timerid"].asInteger());
  if (!timer)
    return InvalidParams;

  HandleFileItem("timerid", false, "timerdetails", CFileItemPtr(new CFileItem(*timer)), parameterObject, parameterObject["properties"], result, false);

  return OK;
}
Esempio n. 10
0
void CEpgContainer::Clear(bool bClearDb /* = false */)
{
  /* make sure the update thread is stopped */
  bool bThreadRunning = !m_bStop;
  if (bThreadRunning && !Stop())
  {
    CLog::Log(LOGERROR, "%s - cannot stop the update thread", __FUNCTION__);
    return;
  }

  if (g_PVRManager.IsStarted())
  {
    // XXX stop the timers from being updated while clearing tags
    /* remove all pointers to epg tables on timers */
    CPVRTimers *timers = g_PVRTimers;
    for (unsigned int iTimerPtr = 0; timers != NULL && iTimerPtr < timers->size(); iTimerPtr++)
      timers->at(iTimerPtr)->SetEpgInfoTag(NULL);
  }

  {
    CSingleLock lock(m_critSection);
    /* clear all epg tables and remove pointers to epg tables on channels */
    for (unsigned int iEpgPtr = 0; iEpgPtr < m_epgs.size(); iEpgPtr++)
      delete m_epgs[iEpgPtr];
    m_epgs.clear();
    m_iNextEpgUpdate  = 0;
    m_bIsInitialising = true;
  }

  /* clear the database entries */
  if (bClearDb && !m_bIgnoreDbForClient)
  {
    if (m_database.Open())
    {
      m_database.DeleteEpg();
      m_database.Close();
    }
  }

  SetChanged();
  NotifyObservers("epg", true);

  if (bThreadRunning)
    Start();
}
Esempio n. 11
0
void CAddonHelpers_PVR::PVRTransferTimerEntry(void *addonData, const PVRHANDLE handle, const PVR_TIMERINFO *timer)
{
  CAddonHelpers* addon = (CAddonHelpers*) addonData;
  if (addon == NULL || handle == NULL || timer == NULL)
  {
    CLog::Log(LOGERROR, "PVR: PVRTransferTimerEntry is called with NULL-Pointer!!!");
    return;
  }

  CPVRTimers *xbmcTimers     = (CPVRTimers*) handle->DATA_ADDRESS;
  CPVRClient* client         = (CPVRClient*) handle->CALLER_ADDRESS;
  const CPVRChannel *channel = CPVRManager::GetChannelGroups()->GetByClientFromAll(timer->channelNum, client->GetClientID());

  if (channel == NULL)
  {
    CLog::Log(LOGERROR, "PVR: PVRTransferTimerEntry is called with not present channel");
    return;
  }

  CPVRTimerInfoTag tag;
  tag.SetClientID(client->GetClientID());
  tag.SetClientIndex(timer->index);
  tag.SetActive(timer->active == 1);
  tag.SetTitle(timer->title);
  tag.SetDir(timer->directory);
  tag.SetClientNumber(timer->channelNum);
  tag.SetStart((time_t) (timer->starttime+client->GetTimeCorrection()));
  tag.SetStop((time_t) (timer->endtime+client->GetTimeCorrection()));
  tag.SetFirstDay((time_t) (timer->firstday+client->GetTimeCorrection()));
  tag.SetPriority(timer->priority);
  tag.SetLifetime(timer->lifetime);
  tag.SetRecording(timer->recording == 1);
  tag.SetRepeating(timer->repeat == 1);
  tag.SetWeekdays(timer->repeatflags);
  CStdString path;
  path.Format("pvr://client%i/timers/%i", tag.ClientID(), tag.ClientIndex());
  tag.SetPath(path);

  xbmcTimers->Update(tag);
  return;
}
Esempio n. 12
0
void CAddonCallbacksPVR::PVRTransferTimerEntry(void *addonData, const ADDON_HANDLE handle, const PVR_TIMER *timer)
{
  if (!handle)
  {
    CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
    return;
  }

  CPVRClient *client     = GetPVRClient(addonData);
  CPVRTimers *xbmcTimers = static_cast<CPVRTimers *>(handle->dataAddress);
  if (!timer || !client || !xbmcTimers)
  {
    CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
    return;
  }

  /* Note: channel can be NULL here, for instance for epg-based timer rules ("record on any channel" condition). */
  CPVRChannelPtr channel = g_PVRChannelGroups->GetByUniqueID(timer->iClientChannelUid, client->GetID());

  /* transfer this entry to the timers container */
  CPVRTimerInfoTagPtr transferTimer(new CPVRTimerInfoTag(*timer, channel, client->GetID()));
  xbmcTimers->UpdateFromClient(transferTimer);
}
Esempio n. 13
0
bool CPVREpgInfoTag::HasTimer(void) const
{
  bool bReturn = false;

  if (m_Timer == NULL)
  {
    CPVRTimers *timers = CPVRManager::GetTimers();
    for (unsigned int iTimerPtr = 0; iTimerPtr < timers->size(); iTimerPtr++)
    {
      if (timers->at(iTimerPtr)->EpgInfoTag() == this)
      {
        bReturn = true;
        break;
      }
    }
  }
  else
  {
    bReturn = true;
  }

  return bReturn;
}
Esempio n. 14
0
bool CPVRTimers::UpdateEntries(const CPVRTimers &timers)
{
  bool bChanged(false);
  bool bAddedOrDeleted(false);
  std::vector<std::string> timerNotifications;

  CSingleLock lock(m_critSection);

  /* go through the timer list and check for updated or new timers */
  for (MapTags::const_iterator it = timers.m_tags.begin(); it != timers.m_tags.end(); ++it)
  {
    for (VecTimerInfoTag::const_iterator timerIt = it->second->begin(); timerIt != it->second->end(); ++timerIt)
    {
      /* check if this timer is present in this container */
      CPVRTimerInfoTagPtr existingTimer = GetByClient((*timerIt)->m_iClientId, (*timerIt)->m_iClientIndex);
      if (existingTimer)
      {
        /* if it's present, update the current tag */
        bool bStateChanged(existingTimer->m_state != (*timerIt)->m_state);
        if (existingTimer->UpdateEntry(*timerIt))
        {
          bChanged = true;
          UpdateEpgEvent(existingTimer);

          if (bStateChanged && g_PVRManager.IsStarted())
          {
            std::string strMessage;
            existingTimer->GetNotificationText(strMessage);
            timerNotifications.push_back(strMessage);
          }

          CLog::Log(LOGDEBUG,"PVRTimers - %s - updated timer %d on client %d",
              __FUNCTION__, (*timerIt)->m_iClientIndex, (*timerIt)->m_iClientId);
        }
      }
      else
      {
        /* new timer */
        CPVRTimerInfoTagPtr newTimer = CPVRTimerInfoTagPtr(new CPVRTimerInfoTag);
        newTimer->UpdateEntry(*timerIt);
        UpdateEpgEvent(newTimer);

        VecTimerInfoTag* addEntry = NULL;
        MapTags::iterator itr = m_tags.find(newTimer->StartAsUTC());
        if (itr == m_tags.end())
        {
          addEntry = new VecTimerInfoTag;
          m_tags.insert(std::make_pair(newTimer->StartAsUTC(), addEntry));
        }
        else
        {
          addEntry = itr->second;
        }

        newTimer->m_iTimerId = ++m_iLastId;
        addEntry->push_back(newTimer);
        UpdateEpgEvent(newTimer);
        bChanged = true;
        bAddedOrDeleted = true;

        if (g_PVRManager.IsStarted())
        {
          std::string strMessage;
          newTimer->GetNotificationText(strMessage);
          timerNotifications.push_back(strMessage);
        }

        CLog::Log(LOGDEBUG,"PVRTimers - %s - added timer %d on client %d",
            __FUNCTION__, (*timerIt)->m_iClientIndex, (*timerIt)->m_iClientId);
      }
    }
  }

  /* to collect timer with changed starting time */
  VecTimerInfoTag timersToMove;

  /* check for deleted timers */
  for (MapTags::iterator it = m_tags.begin(); it != m_tags.end();)
  {
    for (std::vector<CPVRTimerInfoTagPtr>::iterator it2 = it->second->begin(); it2 != it->second->end();)
    {
      CPVRTimerInfoTagPtr timer(*it2);
      if (!timers.GetByClient(timer->m_iClientId, timer->m_iClientIndex))
      {
        /* timer was not found */
        CLog::Log(LOGDEBUG,"PVRTimers - %s - deleted timer %d on client %d",
            __FUNCTION__, timer->m_iClientIndex, timer->m_iClientId);

        if (g_PVRManager.IsStarted())
          timerNotifications.push_back(timer->GetDeletedNotificationText());

        /** clear the EPG tag explicitly here, because it no longer happens automatically with shared pointers */
        timer->ClearEpgTag();
        it2 = it->second->erase(it2);

        bChanged = true;
        bAddedOrDeleted = true;
      }
      else if (timer->StartAsUTC() != it->first)
      {
        /* timer start has changed */
        CLog::Log(LOGDEBUG,"PVRTimers - %s - changed start time timer %d on client %d",
            __FUNCTION__, timer->m_iClientIndex, timer->m_iClientId);

        timer->ClearEpgTag();

        /* remember timer */
        timersToMove.push_back(timer);

        /* remove timer for now, reinsert later */
        it2 = it->second->erase(it2);

        bChanged = true;
        bAddedOrDeleted = true;
      }
      else
      {
        ++it2;
      }
    }
    if (it->second->empty())
      it = m_tags.erase(it);
    else
      ++it;
  }

  /* reinsert timers with changed timer start */
  for (VecTimerInfoTag::const_iterator timerIt = timersToMove.begin(); timerIt != timersToMove.end(); ++timerIt)
  {
    VecTimerInfoTag* addEntry = NULL;
    MapTags::const_iterator itr = m_tags.find((*timerIt)->StartAsUTC());
    if (itr == m_tags.end())
    {
      addEntry = new VecTimerInfoTag;
      m_tags.insert(std::make_pair((*timerIt)->StartAsUTC(), addEntry));
    }
    else
    {
      addEntry = itr->second;
    }

    addEntry->push_back(*timerIt);
    UpdateEpgEvent(*timerIt);
  }

  m_bIsUpdating = false;
  if (bChanged)
  {
    UpdateChannels();
    SetChanged();
    lock.Leave();

    NotifyObservers(bAddedOrDeleted ? ObservableMessageTimersReset : ObservableMessageTimers);

    if (CSettings::GetInstance().GetBool(CSettings::SETTING_PVRRECORD_TIMERNOTIFICATIONS))
    {
      /* queue notifications */
      for (unsigned int iNotificationPtr = 0; iNotificationPtr < timerNotifications.size(); iNotificationPtr++)
      {
        CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info,
            g_localizeStrings.Get(19166),
            timerNotifications.at(iNotificationPtr));
      }
    }
  }

  return bChanged;
}
bool CPVRTimers::UpdateEntries(const CPVRTimers &timers)
{
  bool bChanged(false);
  bool bAddedOrDeleted(false);
  vector<CStdString> timerNotifications;

  CSingleLock lock(m_critSection);

  /* go through the timer list and check for updated or new timers */
  for (map<CDateTime, vector<CPVRTimerInfoTagPtr>* >::const_iterator it = timers.m_tags.begin(); it != timers.m_tags.end(); it++)
  {
    for (vector<CPVRTimerInfoTagPtr>::const_iterator timerIt = it->second->begin(); timerIt != it->second->end(); timerIt++)
    {
      /* check if this timer is present in this container */
      CPVRTimerInfoTagPtr existingTimer = GetByClient((*timerIt)->m_iClientId, (*timerIt)->m_iClientIndex);
      if (existingTimer)
      {
        /* if it's present, update the current tag */
        bool bStateChanged(existingTimer->m_state != (*timerIt)->m_state);
        if (existingTimer->UpdateEntry(*(*timerIt)))
        {
          bChanged = true;
          UpdateEpgEvent(existingTimer);

          if (bStateChanged && g_PVRManager.IsStarted())
          {
            CStdString strMessage;
            existingTimer->GetNotificationText(strMessage);
            timerNotifications.push_back(strMessage);
          }

          CLog::Log(LOGDEBUG,"PVRTimers - %s - updated timer %d on client %d",
              __FUNCTION__, (*timerIt)->m_iClientIndex, (*timerIt)->m_iClientId);
        }
      }
      else
      {
        /* new timer */
        CPVRTimerInfoTagPtr newTimer = CPVRTimerInfoTagPtr(new CPVRTimerInfoTag);
        newTimer->UpdateEntry(*(*timerIt));
        UpdateEpgEvent(newTimer);

        vector<CPVRTimerInfoTagPtr>* addEntry = NULL;
        map<CDateTime, vector<CPVRTimerInfoTagPtr>* >::iterator itr = m_tags.find(newTimer->StartAsUTC());
        if (itr == m_tags.end())
        {
          addEntry = new vector<CPVRTimerInfoTagPtr>;
          m_tags.insert(make_pair(newTimer->StartAsUTC(), addEntry));
        }
        else
        {
          addEntry = itr->second;
        }

        addEntry->push_back(newTimer);
        UpdateEpgEvent(newTimer);
        bChanged = true;
        bAddedOrDeleted = true;

        if (g_PVRManager.IsStarted())
        {
          CStdString strMessage;
          newTimer->GetNotificationText(strMessage);
          timerNotifications.push_back(strMessage);
        }

        CLog::Log(LOGDEBUG,"PVRTimers - %s - added timer %d on client %d",
            __FUNCTION__, (*timerIt)->m_iClientIndex, (*timerIt)->m_iClientId);
      }
    }
  }

  /* to collect timer with changed starting time */
  vector<CPVRTimerInfoTagPtr> timersToMove;
  
  /* check for deleted timers */
  for (map<CDateTime, vector<CPVRTimerInfoTagPtr>* >::iterator it = m_tags.begin(); it != m_tags.end();)
  {
    for (int iTimerPtr = it->second->size() - 1; iTimerPtr >= 0; iTimerPtr--)
    {
      CPVRTimerInfoTagPtr timer = it->second->at(iTimerPtr);
      if (!timers.GetByClient(timer->m_iClientId, timer->m_iClientIndex))
      {
        /* timer was not found */
        CLog::Log(LOGDEBUG,"PVRTimers - %s - deleted timer %d on client %d",
            __FUNCTION__, timer->m_iClientIndex, timer->m_iClientId);

        if (g_PVRManager.IsStarted())
        {
          CStdString strMessage;
          strMessage.Format("%s: '%s'",
              (timer->EndAsUTC() <= CDateTime::GetCurrentDateTime().GetAsUTCDateTime()) ?
                  g_localizeStrings.Get(19227) :
                  g_localizeStrings.Get(19228),
                  timer->m_strTitle.c_str());
          timerNotifications.push_back(strMessage);
        }

        it->second->erase(it->second->begin() + iTimerPtr);

        bChanged = true;
        bAddedOrDeleted = true;
      }
      else if (timer->StartAsUTC() != it->first)
      {
        /* timer start has changed */
        CLog::Log(LOGDEBUG,"PVRTimers - %s - changed start time timer %d on client %d",
            __FUNCTION__, timer->m_iClientIndex, timer->m_iClientId);

        timer->ClearEpgTag();

        /* remember timer */
        timersToMove.push_back(timer);
        
        /* remove timer for now, reinsert later */
        it->second->erase(it->second->begin() + iTimerPtr);

        bChanged = true;
        bAddedOrDeleted = true;
      }
    }
    if (it->second->size() == 0)
      m_tags.erase(it++);
    else
      ++it;
  }

  /* reinsert timers with changed timer start */
  for (vector<CPVRTimerInfoTagPtr>::const_iterator timerIt = timersToMove.begin(); timerIt != timersToMove.end(); timerIt++)
  {
      vector<CPVRTimerInfoTagPtr>* addEntry = NULL;
      map<CDateTime, vector<CPVRTimerInfoTagPtr>* >::const_iterator itr = m_tags.find((*timerIt)->StartAsUTC());
      if (itr == m_tags.end())
      {
        addEntry = new vector<CPVRTimerInfoTagPtr>;
        m_tags.insert(make_pair((*timerIt)->StartAsUTC(), addEntry));
      }
      else
      {
        addEntry = itr->second;
      }

      addEntry->push_back(*timerIt);
      UpdateEpgEvent(*timerIt);
  }

  m_bIsUpdating = false;
  if (bChanged)
  {
    UpdateChannels();
    SetChanged();
    lock.Leave();

    NotifyObservers(bAddedOrDeleted ? ObservableMessageTimersReset : ObservableMessageTimers);

    if (g_guiSettings.GetBool("pvrrecord.timernotifications"))
    {
      /* queue notifications */
      for (unsigned int iNotificationPtr = 0; iNotificationPtr < timerNotifications.size(); iNotificationPtr++)
      {
        CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info,
            g_localizeStrings.Get(19166),
            timerNotifications.at(iNotificationPtr));
      }
    }
  }

  return bChanged;
}
Esempio n. 16
0
bool CPVRTimers::UpdateEntries(const CPVRTimers &timers, const std::vector<int> &failedClients)
{
  bool bChanged(false);
  bool bAddedOrDeleted(false);
  std::vector< std::pair< int, std::string> > timerNotifications;

  CSingleLock lock(m_critSection);

  /* go through the timer list and check for updated or new timers */
  for (MapTags::const_iterator it = timers.m_tags.begin(); it != timers.m_tags.end(); ++it)
  {
    for (VecTimerInfoTag::const_iterator timerIt = it->second->begin(); timerIt != it->second->end(); ++timerIt)
    {
      /* check if this timer is present in this container */
      CPVRTimerInfoTagPtr existingTimer = GetByClient((*timerIt)->m_iClientId, (*timerIt)->m_iClientIndex);
      if (existingTimer)
      {
        /* if it's present, update the current tag */
        bool bStateChanged(existingTimer->m_state != (*timerIt)->m_state);
        if (existingTimer->UpdateEntry(*timerIt))
        {
          bChanged = true;
          existingTimer->ResetChildState();

          if (bStateChanged && g_PVRManager.IsStarted())
          {
            std::string strMessage;
            existingTimer->GetNotificationText(strMessage);
            timerNotifications.push_back(std::make_pair((*timerIt)->m_iClientId, strMessage));
          }

          CLog::Log(LOGDEBUG,"PVRTimers - %s - updated timer %d on client %d",
              __FUNCTION__, (*timerIt)->m_iClientIndex, (*timerIt)->m_iClientId);
        }
      }
      else
      {
        /* new timer */
        CPVRTimerInfoTagPtr newTimer = CPVRTimerInfoTagPtr(new CPVRTimerInfoTag);
        newTimer->UpdateEntry(*timerIt);

        VecTimerInfoTag* addEntry = NULL;
        MapTags::iterator itr = m_tags.find(newTimer->m_bStartAnyTime ? CDateTime() : newTimer->StartAsUTC());
        if (itr == m_tags.end())
        {
          addEntry = new VecTimerInfoTag;
          m_tags.insert(std::make_pair(newTimer->m_bStartAnyTime ? CDateTime() : newTimer->StartAsUTC(), addEntry));
        }
        else
        {
          addEntry = itr->second;
        }

        newTimer->m_iTimerId = ++m_iLastId;
        addEntry->push_back(newTimer);
        bChanged = true;
        bAddedOrDeleted = true;

        if (g_PVRManager.IsStarted())
        {
          std::string strMessage;
          newTimer->GetNotificationText(strMessage);
          timerNotifications.push_back(std::make_pair(newTimer->m_iClientId, strMessage));
        }

        CLog::Log(LOGDEBUG,"PVRTimers - %s - added timer %d on client %d",
            __FUNCTION__, (*timerIt)->m_iClientIndex, (*timerIt)->m_iClientId);
      }
    }
  }

  /* to collect timer with changed starting time */
  VecTimerInfoTag timersToMove;

  /* check for deleted timers */
  for (MapTags::iterator it = m_tags.begin(); it != m_tags.end();)
  {
    for (std::vector<CPVRTimerInfoTagPtr>::iterator it2 = it->second->begin(); it2 != it->second->end();)
    {
      CPVRTimerInfoTagPtr timer(*it2);
      if (!timers.GetByClient(timer->m_iClientId, timer->m_iClientIndex))
      {
        /* timer was not found */
        bool bIgnoreTimer(false);
        for (const auto &failedClient : failedClients)
        {
          if (failedClient == timer->m_iClientId)
          {
            bIgnoreTimer = true;
            break;
          }
        }

        if (bIgnoreTimer)
        {
          ++it2;
          continue;
        }

        CLog::Log(LOGDEBUG,"PVRTimers - %s - deleted timer %d on client %d",
            __FUNCTION__, timer->m_iClientIndex, timer->m_iClientId);

        if (g_PVRManager.IsStarted())
          timerNotifications.push_back(std::make_pair(timer->m_iClientId, timer->GetDeletedNotificationText()));

        /** clear the EPG tag explicitly here, because it no longer happens automatically with shared pointers */
        timer->ClearEpgTag();
        it2 = it->second->erase(it2);

        bChanged = true;
        bAddedOrDeleted = true;
      }
      else if ((timer->m_bStartAnyTime && it->first != CDateTime()) ||
               (!timer->m_bStartAnyTime && timer->StartAsUTC() != it->first))
      {
        /* timer start has changed */
        CLog::Log(LOGDEBUG,"PVRTimers - %s - changed start time timer %d on client %d",
            __FUNCTION__, timer->m_iClientIndex, timer->m_iClientId);

        timer->ClearEpgTag();

        /* remember timer */
        timersToMove.push_back(timer);

        /* remove timer for now, reinsert later */
        it2 = it->second->erase(it2);

        bChanged = true;
        bAddedOrDeleted = true;
      }
      else
      {
        ++it2;
      }
    }
    if (it->second->empty())
      it = m_tags.erase(it);
    else
      ++it;
  }

  /* reinsert timers with changed timer start */
  for (VecTimerInfoTag::const_iterator timerIt = timersToMove.begin(); timerIt != timersToMove.end(); ++timerIt)
  {
    VecTimerInfoTag* addEntry = NULL;
    MapTags::const_iterator itr = m_tags.find((*timerIt)->m_bStartAnyTime ? CDateTime() : (*timerIt)->StartAsUTC());
    if (itr == m_tags.end())
    {
      addEntry = new VecTimerInfoTag;
      m_tags.insert(std::make_pair((*timerIt)->m_bStartAnyTime ? CDateTime() : (*timerIt)->StartAsUTC(), addEntry));
    }
    else
    {
      addEntry = itr->second;
    }

    addEntry->push_back(*timerIt);
  }

  /* update child information for all parent timers */
  for (const auto &tagsEntry : m_tags)
  {
    for (const auto &timersEntry : *tagsEntry.second)
    {
      if (timersEntry->GetTimerRuleId() != PVR_TIMER_NO_PARENT)
      {
        const CPVRTimerInfoTagPtr parentTimer(GetByClient(timersEntry->m_iClientId, timersEntry->GetTimerRuleId()));
        if (parentTimer)
          parentTimer->UpdateChildState(timersEntry);
      }
    }
  }

  m_bIsUpdating = false;
  if (bChanged)
  {
    UpdateChannels();
    SetChanged();
    lock.Leave();

    NotifyObservers(bAddedOrDeleted ? ObservableMessageTimersReset : ObservableMessageTimers);

    /* queue notifications / fill eventlog */
    for (const auto &entry : timerNotifications)
    {
      if (CSettings::GetInstance().GetBool(CSettings::SETTING_PVRRECORD_TIMERNOTIFICATIONS))
        CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(19166), entry.second);

      std::string strName;
      g_PVRClients->GetClientAddonName(entry.first, strName);

      std::string strIcon;
      g_PVRClients->GetClientAddonIcon(entry.first, strIcon);

      CEventLog::GetInstance().Add(EventPtr(new CNotificationEvent(strName, entry.second, strIcon, EventLevel::Information)));
    }
  }

  return bChanged;
}