Example #1
0
bool CPVRChannelGroup::AddToGroup(const CPVRChannelPtr &channel, int iChannelNumber /* = 0 */)
{
  CSingleLock lock(m_critSection);

  bool bReturn(false);

  if (!CPVRChannelGroup::IsGroupMember(channel))
  {
    if (iChannelNumber <= 0 || iChannelNumber > (int) m_members.size() + 1)
      iChannelNumber = m_members.size() + 1;

    CPVRChannelPtr realChannel = (IsInternalGroup()) ?
        GetByClient(channel->UniqueID(), channel->ClientID()) :
        g_PVRChannelGroups->GetGroupAll(m_bRadio)->GetByClient(channel->UniqueID(), channel->ClientID());

    if (realChannel)
    {
      PVRChannelGroupMember newMember = { realChannel, (unsigned int)iChannelNumber };
      m_members.push_back(newMember);
      m_bChanged = true;

      SortAndRenumber();

      // TODO notify observers
      bReturn = true;
    }
  }

  return bReturn;
}
Example #2
0
bool CPVRChannelGroup::RemoveDeletedChannels(const CPVRChannelGroup &channels)
{
  bool bReturn(false);
  CSingleLock lock(m_critSection);

  /* check for deleted channels */
  for (int iChannelPtr = m_members.size() - 1; iChannelPtr >= 0; iChannelPtr--)
  {
    CPVRChannelPtr channel = m_members.at(iChannelPtr).channel;
    if (!channel)
      continue;

    if (channels.GetByClient(channel->UniqueID(), channel->ClientID()) == NULL)
    {
      /* channel was not found */
      CLog::Log(LOGINFO,"PVRChannelGroup - %s - deleted %s channel '%s' from group '%s'",
          __FUNCTION__, m_bRadio ? "radio" : "TV", channel->ChannelName().c_str(), GroupName().c_str());

      /* remove this channel from all non-system groups if this is the internal group */
      if (IsInternalGroup())
      {
        g_PVRChannelGroups->Get(m_bRadio)->RemoveFromAllGroups(*channel);

        /* since it was not found in the internal group, it was deleted from the backend */
        channel->Delete();
      }

      m_members.erase(m_members.begin() + iChannelPtr);
      m_bChanged = true;
      bReturn = true;
    }
  }

  return bReturn;
}
Example #3
0
CPVRTimerInfoTag::CPVRTimerInfoTag(const PVR_TIMER &timer, const CPVRChannelPtr &channel, unsigned int iClientId) :
    m_strTitle(timer.strTitle),
    m_strDirectory(timer.strDirectory)
{
    m_iClientId          = iClientId;
    m_iClientIndex       = timer.iClientIndex;
    m_iClientChannelUid  = channel ? channel->UniqueID() : timer.iClientChannelUid;
    m_iChannelNumber     = channel ? g_PVRChannelGroups->GetGroupAll(channel->IsRadio())->GetChannelNumber(channel) : 0;
    m_StartTime          = timer.startTime + g_advancedSettings.m_iPVRTimeCorrection;
    m_StopTime           = timer.endTime + g_advancedSettings.m_iPVRTimeCorrection;
    m_bIsRepeating       = timer.bIsRepeating;
    m_FirstDay           = timer.firstDay + g_advancedSettings.m_iPVRTimeCorrection;
    m_iWeekdays          = timer.iWeekdays;
    m_iPriority          = timer.iPriority;
    m_iLifetime          = timer.iLifetime;
    m_iMarginStart       = timer.iMarginStart;
    m_iMarginEnd         = timer.iMarginEnd;
    m_genre              = StringUtils::Split(CEpg::ConvertGenreIdToString(timer.iGenreType, timer.iGenreSubType), g_advancedSettings.m_videoItemSeparator);
    m_iGenreType         = timer.iGenreType;
    m_iGenreSubType      = timer.iGenreSubType;
    CEpgInfoTagPtr emptyTag;
    m_epgTag             = emptyTag;
    m_channel            = channel;
    m_bIsRadio           = channel && channel->IsRadio();
    m_state              = timer.state;
    m_strFileNameAndPath = StringUtils::Format("pvr://client%i/timers/%i", m_iClientId, m_iClientIndex);
    m_iTimerId           = 0;

    UpdateSummary();
}
Example #4
0
CFileItemPtr CPVRTimers::GetTimerForEpgTag(const CFileItem *item) const
{
  if (item && item->HasEPGInfoTag() && item->GetEPGInfoTag()->ChannelTag())
  {
    const CEpgInfoTagPtr epgTag(item->GetEPGInfoTag());
    const CPVRChannelPtr channel(epgTag->ChannelTag());
    CSingleLock lock(m_critSection);

    for (MapTags::const_iterator it = m_tags.begin(); it != m_tags.end(); ++it)
    {
      for (VecTimerInfoTag::const_iterator timerIt = it->second->begin(); timerIt != it->second->end(); ++timerIt)
      {
        CPVRTimerInfoTagPtr timer = *timerIt;

        if (timer->GetEpgInfoTag() == epgTag || 
            (timer->m_iClientChannelUid == channel->UniqueID() &&
            timer->m_bIsRadio == channel->IsRadio() &&
            timer->StartAsUTC() <= epgTag->StartAsUTC() &&
            timer->EndAsUTC() >= epgTag->EndAsUTC()))
        {
          CFileItemPtr fileItem(new CFileItem(timer));
          return fileItem;
        }
      }
    }
  }

  CFileItemPtr fileItem;
  return fileItem;
}
Example #5
0
CPVRTimerInfoTagPtr CPVRTimerInfoTag::CreateInstantTimerTag(const CPVRChannelPtr &channel)
{
  if (!channel)
  {
    CLog::Log(LOGERROR, "%s - no channel set", __FUNCTION__);
    return CPVRTimerInfoTagPtr();
  }

  CEpgInfoTagPtr epgTag(channel->GetEPGNow());
  CPVRTimerInfoTagPtr newTimer;
  if (epgTag)
    newTimer = CreateFromEpg(epgTag);

  if (!newTimer)
  {
    newTimer.reset(new CPVRTimerInfoTag);

    newTimer->m_iClientIndex       = PVR_TIMER_NO_CLIENT_INDEX;
    newTimer->m_iParentClientIndex = PVR_TIMER_NO_PARENT;
    newTimer->m_channel            = channel;
    newTimer->m_strTitle           = channel->ChannelName();
    newTimer->m_iChannelNumber     = channel->ChannelNumber();
    newTimer->m_iClientChannelUid  = channel->UniqueID();
    newTimer->m_iClientId          = channel->ClientID();
    newTimer->m_bIsRadio           = channel->IsRadio();

    // timertype: manual one-shot timer for given client
    CPVRTimerTypePtr timerType(CPVRTimerType::CreateFromAttributes(
      PVR_TIMER_TYPE_IS_MANUAL, PVR_TIMER_TYPE_IS_REPEATING | PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES, channel->ClientID()));
    if (!timerType)
    {
      CLog::Log(LOGERROR, "%s - unable to create one shot manual timer type", __FUNCTION__);
      return CPVRTimerInfoTagPtr();
    }

    newTimer->SetTimerType(timerType);
  }

  // no matter the timer was created from an epg tag, set special instant timer start and end times.
  CDateTime startTime(0);
  newTimer->SetStartFromUTC(startTime);
  newTimer->m_iMarginStart = 0; /* set the start margin to 0 for instant timers */

  int iDuration = CSettings::GetInstance().GetInt(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME);
  CDateTime endTime = CDateTime::GetUTCDateTime() + CDateTimeSpan(0, 0, iDuration ? iDuration : 120, 0);
  newTimer->SetEndFromUTC(endTime);

  /* update summary string according to changed start/end time */
  newTimer->UpdateSummary();

  /* set epg tag at timer & timer at epg tag */
  newTimer->UpdateEpgInfoTag();

  /* unused only for reference */
  newTimer->m_strFileNameAndPath = CPVRTimersPath::PATH_NEW;

  return newTimer;
}
Example #6
0
bool CPVRTimers::InstantTimer(const CPVRChannelPtr &channel)
{
  assert(channel.get());

  if (!g_PVRManager.CheckParentalLock(channel))
    return false;

  CEpgInfoTagPtr epgTag(channel->GetEPGNow());
  CPVRTimerInfoTagPtr newTimer;
  if (epgTag)
    newTimer = CPVRTimerInfoTag::CreateFromEpg(epgTag);

  if (!newTimer)
  {
    newTimer.reset(new CPVRTimerInfoTag);
    /* set the timer data */
    newTimer->m_iClientIndex      = -1;
    newTimer->m_strTitle          = channel->ChannelName();
    newTimer->m_strSummary        = g_localizeStrings.Get(19056);
    newTimer->m_iChannelNumber    = channel->ChannelNumber();
    newTimer->m_iClientChannelUid = channel->UniqueID();
    newTimer->m_iClientId         = channel->ClientID();
    newTimer->m_bIsRadio          = channel->IsRadio();

    /* generate summary string */
    newTimer->m_strSummary = StringUtils::Format("%s %s %s %s %s",
                                                 newTimer->StartAsLocalTime().GetAsLocalizedDate().c_str(),
                                                 g_localizeStrings.Get(19159).c_str(),
                                                 newTimer->StartAsLocalTime().GetAsLocalizedTime("", false).c_str(),
                                                 g_localizeStrings.Get(19160).c_str(),
                                                 newTimer->EndAsLocalTime().GetAsLocalizedTime("", false).c_str());
  }

  CDateTime startTime(0);
  newTimer->SetStartFromUTC(startTime);
  newTimer->m_iMarginStart = 0; /* set the start margin to 0 for instant timers */

  int iDuration = CSettings::GetInstance().GetInt(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME);
  CDateTime endTime = CDateTime::GetUTCDateTime() + CDateTimeSpan(0, 0, iDuration ? iDuration : 120, 0);
  newTimer->SetEndFromUTC(endTime);

  /* unused only for reference */
  newTimer->m_strFileNameAndPath = CPVRTimersPath::PATH_NEW;

  bool bReturn = newTimer->AddToClient();
  if (!bReturn)
    CLog::Log(LOGERROR, "PVRTimers - %s - unable to add an instant timer on the client", __FUNCTION__);

  return bReturn;
}
Example #7
0
bool CPVRClient::OpenStream(const CPVRChannelPtr &channel, bool bIsSwitchingChannel)
{
  bool bReturn(false);
  CloseStream();

  if(!CanPlayChannel(channel))
  {
    CLog::Log(LOGDEBUG, "add-on '%s' can not play channel '%s'", GetFriendlyName().c_str(), channel->ChannelName().c_str());
  }
  else if (!channel->StreamURL().empty())
  {
    CLog::Log(LOGDEBUG, "opening live stream on url '%s'", channel->StreamURL().c_str());
    bReturn = true;

    // the Njoy N7 sometimes doesn't switch channels, but opens a stream to the previous channel
    // when not waiting for a short period.
    // added in 1.1.0
    AddonVersion checkVersion("1.1.0");
    if (m_apiVersion >= checkVersion)
    {
      unsigned int iWaitTimeMs = m_pStruct->GetChannelSwitchDelay();
      if (iWaitTimeMs > 0)
        XbmcThreads::ThreadSleep(iWaitTimeMs);
    }
  }
  else
  {
    CLog::Log(LOGDEBUG, "opening live stream for channel '%s'", channel->ChannelName().c_str());
    PVR_CHANNEL tag;
    WriteClientChannelInfo(channel, tag);

    try
    {
      bReturn = m_pStruct->OpenLiveStream(tag);
    }
    catch (std::exception &e) { LogException(e, __FUNCTION__); }
  }

  if (bReturn)
  {
    CPVRChannelPtr currentChannel(g_PVRChannelGroups->GetByUniqueID(channel->UniqueID(), channel->ClientID()));
    CSingleLock lock(m_critSection);
    m_playingChannel      = currentChannel;
    m_bIsPlayingTV        = true;
    m_bIsPlayingRecording = false;
  }

  return bReturn;
}
void CGUIEPGGridContainerModel::FindChannelAndBlockIndex(int channelUid, unsigned int broadcastUid, int eventOffset, int &newChannelIndex, int &newBlockIndex) const
{
  const CDateTimeSpan blockDuration(0, 0, MINSPERBLOCK, 0);
  bool bFoundPrevChannel = false;

  for (size_t channel = 0; channel < m_channelItems.size(); ++channel)
  {
    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();
    CEpgInfoTagPtr tag;
    CPVRChannelPtr chan;

    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)
          {
            newChannelIndex = channel;
            newBlockIndex   = block + eventOffset;
            return; // both found. done.
          }
          if (!bFoundPrevChannel && channelUid > -1)
          {
            chan = tag->ChannelTag();
            if (chan && chan->UniqueID() == channelUid)
            {
              newChannelIndex = channel;
              bFoundPrevChannel = true;
            }
          }
          break; // next block
        }
        progIdx++;
      }
      gridCursor += blockDuration;
    }
  }
}
Example #9
0
CPVRTimerInfoTagPtr CPVRTimers::GetActiveTimerForChannel(const CPVRChannelPtr &channel) const
{
  CSingleLock lock(m_critSection);
  for (const auto &tagsEntry : m_tags)
  {
    for (const auto &timersEntry : *tagsEntry.second)
    {
      if (timersEntry->IsRecording() &&
          timersEntry->m_iClientChannelUid == channel->UniqueID() &&
          timersEntry->m_iClientId == channel->ClientID())
        return timersEntry;
    }
  }

  return CPVRTimerInfoTagPtr();
}
Example #10
0
/*!
 * @brief Copy over channel info from xbmcChannel to addonClient.
 * @param xbmcChannel The channel on XBMC's side.
 * @param addonChannel The channel on the addon's side.
 */
void CPVRClient::WriteClientChannelInfo(const CPVRChannelPtr &xbmcChannel, PVR_CHANNEL &addonChannel)
{
  assert(xbmcChannel.get());

  memset(&addonChannel, 0, sizeof(addonChannel));

  addonChannel.iUniqueId         = xbmcChannel->UniqueID();
  addonChannel.iChannelNumber    = xbmcChannel->ClientChannelNumber();
  addonChannel.iSubChannelNumber = xbmcChannel->ClientSubChannelNumber();
  strncpy(addonChannel.strChannelName, xbmcChannel->ClientChannelName().c_str(), sizeof(addonChannel.strChannelName) - 1);
  strncpy(addonChannel.strIconPath, xbmcChannel->IconPath().c_str(), sizeof(addonChannel.strIconPath) - 1);
  addonChannel.iEncryptionSystem = xbmcChannel->EncryptionSystem();
  addonChannel.bIsRadio          = xbmcChannel->IsRadio();
  addonChannel.bIsHidden         = xbmcChannel->IsHidden();
  strncpy(addonChannel.strInputFormat, xbmcChannel->InputFormat().c_str(), sizeof(addonChannel.strInputFormat) - 1);
  strncpy(addonChannel.strStreamURL, xbmcChannel->StreamURL().c_str(), sizeof(addonChannel.strStreamURL) - 1);
}
Example #11
0
void CPVRChannelGroup::RemoveInvalidChannels(void)
{
  CPVRChannelPtr channel;
  CSingleLock lock(m_critSection);
  for (PVR_CHANNEL_GROUP_SORTED_MEMBERS::iterator it = m_sortedMembers.begin(); it != m_sortedMembers.end();)
  {
    bool bDelete = false;
    channel = (*it).channel;

    if (channel->ClientChannelNumber() <= 0)
    {
      CLog::Log(LOGERROR, "PVRChannelGroup - %s - removing invalid channel '%s' from client '%i': no valid client channel number",
          __FUNCTION__, channel->ChannelName().c_str(), channel->ClientID());
      bDelete = true;
    }

    if (!bDelete && channel->UniqueID() <= 0)
    {
      CLog::Log(LOGERROR, "PVRChannelGroup - %s - removing invalid channel '%s' from client '%i': no valid unique ID",
          __FUNCTION__, channel->ChannelName().c_str(), channel->ClientID());
      bDelete = true;
    }

    /* remove this channel from all non-system groups if this is the internal group */
    if (bDelete)
    {
      if (IsInternalGroup())
      {
        g_PVRChannelGroups->Get(m_bRadio)->RemoveFromAllGroups(channel);
        channel->Delete();
      }
      else
      {
        m_members.erase(channel->StorageId());
        it = m_sortedMembers.erase(it);
      }
      m_bChanged = true;
    }
    else
    {
      ++it;
    }
  }
}
Example #12
0
bool CPVRClient::SwitchChannel(const CPVRChannelPtr &channel)
{
  bool bSwitched(false);

  if (IsPlayingLiveStream() && CanPlayChannel(channel))
  {
    PVR_CHANNEL tag;
    WriteClientChannelInfo(channel, tag);
    bSwitched = m_struct.SwitchChannel(tag);
  }

  if (bSwitched)
  {
    CPVRChannelPtr currentChannel(g_PVRChannelGroups->GetByUniqueID(channel->UniqueID(), channel->ClientID()));
    CSingleLock lock(m_critSection);
    m_playingChannel = currentChannel;
  }

  return bSwitched;
}
Example #13
0
void CPVRChannelGroup::RemoveInvalidChannels(void)
{
  bool bDelete(false);
  CSingleLock lock(m_critSection);
  for (unsigned int ptr = 0; ptr < m_members.size(); ptr--)
  {
    bDelete = false;
    CPVRChannelPtr channel = m_members.at(ptr).channel;
    if (channel->IsVirtual())
      continue;

    if (m_members.at(ptr).channel->ClientChannelNumber() <= 0)
    {
      CLog::Log(LOGERROR, "PVRChannelGroup - %s - removing invalid channel '%s' from client '%i': no valid client channel number",
          __FUNCTION__, channel->ChannelName().c_str(), channel->ClientID());
      bDelete = true;
    }

    if (!bDelete && channel->UniqueID() <= 0)
    {
      CLog::Log(LOGERROR, "PVRChannelGroup - %s - removing invalid channel '%s' from client '%i': no valid unique ID",
          __FUNCTION__, channel->ChannelName().c_str(), channel->ClientID());
      bDelete = true;
    }

    /* remove this channel from all non-system groups if this is the internal group */
    if (bDelete)
    {
      if (IsInternalGroup())
      {
        g_PVRChannelGroups->Get(m_bRadio)->RemoveFromAllGroups(*channel);
        channel->Delete();
      }
      else
      {
        m_members.erase(m_members.begin() + ptr);
      }
      m_bChanged = true;
    }
  }
}
void CGUIDialogPVRTimerSettings::InitializeChannelsList()
{
  m_channelEntries.clear();

  CFileItemList channelsList;
  g_PVRChannelGroups->GetGroupAll(m_bIsRadio)->GetMembers(channelsList);

  for (int i = 0; i < channelsList.Size(); ++i)
  {
    const CPVRChannelPtr channel(channelsList[i]->GetPVRChannelInfoTag());
    std::string channelDescription(
      StringUtils::Format("%i %s", channel->ChannelNumber(), channel->ChannelName().c_str()));
    m_channelEntries.insert(
      std::make_pair(i, ChannelDescriptor(channel->UniqueID(), channel->ClientID(), channelDescription)));
  }

  // Add special "any channel" entry (used for epg-based repeating timers).
  m_channelEntries.insert(
    std::make_pair(
      ENTRY_ANY_CHANNEL, ChannelDescriptor(PVR_CHANNEL_INVALID_UID, 0, g_localizeStrings.Get(809))));
}
Example #15
0
CPVRTimerInfoTagPtr CPVRTimers::GetTimerForEpgTag(const CEpgInfoTagPtr &epgTag) const
{
  if (epgTag)
  {
    // already a timer assigned to tag?
    CPVRTimerInfoTagPtr timer(epgTag->Timer());
    if (timer)
      return timer;

    // try to find a matching timer for the tag.
    if (epgTag->ChannelTag())
    {
      const CPVRChannelPtr channel(epgTag->ChannelTag());
      CSingleLock lock(m_critSection);

      for (MapTags::const_iterator it = m_tags.begin(); it != m_tags.end(); ++it)
      {
        for (VecTimerInfoTag::const_iterator timerIt = it->second->begin(); timerIt != it->second->end(); ++timerIt)
        {
          timer = *timerIt;

          if (!timer->IsRepeating() &&
              (timer->GetEpgInfoTag(false) == epgTag ||
               (timer->m_iEpgUid != EPG_TAG_INVALID_UID && timer->m_iEpgUid == epgTag->UniqueBroadcastID()) ||
               (timer->m_iClientChannelUid == channel->UniqueID() &&
                timer->m_bIsRadio == channel->IsRadio() &&
                timer->StartAsUTC() <= epgTag->StartAsUTC() &&
                timer->EndAsUTC() >= epgTag->EndAsUTC())))
          {
            return timer;
          }
        }
      }
    }
  }

  return CPVRTimerInfoTagPtr();
}
Example #16
0
bool CPVRClient::SwitchChannel(const CPVRChannelPtr &channel)
{
  bool bSwitched(false);

  if (IsPlayingLiveStream() && CanPlayChannel(channel))
  {
    PVR_CHANNEL tag;
    WriteClientChannelInfo(channel, tag);
    try
    {
      bSwitched = m_pStruct->SwitchChannel(tag);
    }
    catch (std::exception &e) { LogException(e, __FUNCTION__); }
  }

  if (bSwitched)
  {
    CPVRChannelPtr currentChannel(g_PVRChannelGroups->GetByUniqueID(channel->UniqueID(), channel->ClientID()));
    CSingleLock lock(m_critSection);
    m_playingChannel = currentChannel;
  }

  return bSwitched;
}
Example #17
0
bool CPVRDatabase::PersistChannels(CPVRChannelGroup &group)
{
  bool bReturn(true);

  CPVRChannelPtr channel;
  for (const auto& groupMember : group.m_members)
  {
    channel = groupMember.second.channel;
    if (channel->IsChanged() || channel->IsNew())
    {
      if (Persist(*channel, false))
      {
        groupMember.second.channel->Persisted();
        bReturn = true;
      }
    }
  }

  bReturn &= CommitInsertQueries();

  if (bReturn)
  {
    std::string strQuery;
    std::string strValue;
    for (const auto& groupMember : group.m_members)
    {
      channel = groupMember.second.channel;
      strQuery = PrepareSQL("iUniqueId = %u AND iClientId = %u", channel->UniqueID(), channel->ClientID());
      strValue = GetSingleValue("channels", "idChannel", strQuery);
      if (!strValue.empty() && StringUtils::IsInteger(strValue))
        channel->SetChannelID(atoi(strValue.c_str()));
    }
  }

  return bReturn;
}
Example #18
0
CPVRTimerInfoTagPtr CPVRTimerInfoTag::CreateFromEpg(const CEpgInfoTagPtr &tag, bool bCreateRule /* = false */)
{
  /* create a new timer */
  CPVRTimerInfoTagPtr newTag(new CPVRTimerInfoTag());

  /* check if a valid channel is set */
  CPVRChannelPtr channel = tag->ChannelTag();
  if (!channel)
  {
    CLog::Log(LOGERROR, "%s - no channel set", __FUNCTION__);
    return CPVRTimerInfoTagPtr();
  }

  /* check if the epg end date is in the future */
  if (tag->EndAsLocalTime() < CDateTime::GetCurrentDateTime() && !bCreateRule)
  {
    CLog::Log(LOGERROR, "%s - end time is in the past", __FUNCTION__);
    return CPVRTimerInfoTagPtr();
  }

  /* set the timer data */
  CDateTime newStart = tag->StartAsUTC();
  CDateTime newEnd = tag->EndAsUTC();
  newTag->m_iClientIndex       = PVR_TIMER_NO_CLIENT_INDEX;
  newTag->m_iParentClientIndex = PVR_TIMER_NO_PARENT;
  newTag->m_strTitle           = tag->Title().empty() ? channel->ChannelName() : tag->Title();
  newTag->m_iChannelNumber     = channel->ChannelNumber();
  newTag->m_iClientChannelUid  = channel->UniqueID();
  newTag->m_iClientId          = channel->ClientID();
  newTag->m_bIsRadio           = channel->IsRadio();
  newTag->m_channel            = channel;
  newTag->m_iEpgUid            = tag->UniqueBroadcastID();
  newTag->SetStartFromUTC(newStart);
  newTag->SetEndFromUTC(newEnd);

  CPVRTimerTypePtr timerType;
  if (bCreateRule)
  {
    // create epg-based timer rule
    timerType = CPVRTimerType::CreateFromAttributes(
      PVR_TIMER_TYPE_IS_REPEATING,
      PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES, channel->ClientID());

    if (timerType)
    {
      if (timerType->SupportsEpgTitleMatch())
        newTag->m_strEpgSearchString = newTag->m_strTitle;

      if (timerType->SupportsWeekdays())
        newTag->m_iWeekdays = PVR_WEEKDAY_ALLDAYS;

      if (timerType->SupportsStartAnyTime())
        newTag->m_bStartAnyTime = true;

      if (timerType->SupportsEndAnyTime())
        newTag->m_bEndAnyTime = true;
    }
  }
  else
  {
    // create one-shot epg-based timer
    timerType = CPVRTimerType::CreateFromAttributes(
      PVR_TIMER_TYPE_ATTRIBUTE_NONE,
      PVR_TIMER_TYPE_IS_REPEATING | PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES, channel->ClientID());
  }

  if (!timerType)
  {
    CLog::Log(LOGERROR, "%s - unable to create any epg-based timer type", __FUNCTION__);
    return CPVRTimerInfoTagPtr();
  }

  newTag->SetTimerType(timerType);
  newTag->UpdateSummary();
  newTag->UpdateEpgInfoTag();

  /* unused only for reference */
  newTag->m_strFileNameAndPath = CPVRTimersPath::PATH_NEW;

  return newTag;
}
Example #19
0
void CGUIDialogPVRTimerSettings::OnSettingChanged(const CSetting *setting)
{
  if (setting == NULL)
    return;

  CGUIDialogSettingsManualBase::OnSettingChanged(setting);

  CPVRTimerInfoTag* tag = m_timerItem->GetPVRTimerInfoTag();
  if (tag == NULL)
    return;

  const std::string &settingId = setting->GetId();
  if (settingId == SETTING_TMR_ACTIVE)
    m_bTimerActive = static_cast<const CSettingBool*>(setting)->GetValue();
  if (settingId == SETTING_TMR_RADIO || settingId == SETTING_TMR_CHNAME_TV || settingId == SETTING_TMR_CHNAME_RADIO)
  {
    if (settingId == SETTING_TMR_RADIO)
    {
      tag->m_bIsRadio = static_cast<const CSettingBool*>(setting)->GetValue();
      m_selectedChannelEntry = 0;
    }
    else
      m_selectedChannelEntry = static_cast<const CSettingInt*>(setting)->GetValue();

    std::map<std::pair<bool, int>, int>::iterator itc = m_channelEntries.find(std::make_pair(tag->m_bIsRadio, m_selectedChannelEntry));
    if (itc != m_channelEntries.end())
    {
      CPVRChannelPtr channel =  g_PVRChannelGroups->GetChannelById(itc->second);
      if (channel)
      {
        tag->m_iClientChannelUid = channel->UniqueID();
        tag->m_iClientId         = channel->ClientID();
        tag->m_bIsRadio          = channel->IsRadio();
        tag->m_iChannelNumber    = channel->ChannelNumber();
      }
      else
      {
        tag->m_iClientChannelUid = PVR_VIRTUAL_CHANNEL_UID;
        tag->m_iClientId         = PVR_VIRTUAL_CLIENT_ID;
        tag->m_iChannelNumber    = 0;
      }
      // Update channel pointer from above values
      tag->UpdateChannel();
    }
  }
  else if (settingId == SETTING_TMR_DAY)
  {
    m_tmp_day = static_cast<const CSettingInt*>(setting)->GetValue();

    if (m_tmp_day <= 10)
      SetTimerFromWeekdaySetting(*tag);
    else
    {
      CDateTime time = CDateTime::GetCurrentDateTime();
      CDateTime timestart = m_timerStartTime;
      CDateTime timestop = m_timerEndTime;
      int m_tmp_diff;

      // get diffence of timer in days between today and timer start date
      tm time_cur; time.GetAsTm(time_cur);
      tm time_tmr; timestart.GetAsTm(time_tmr);

      m_tmp_diff = time_tmr.tm_yday - time_cur.tm_yday;
      if (time_tmr.tm_yday - time_cur.tm_yday < 0)
        m_tmp_diff = 365;

      CDateTime newStart = timestart + CDateTimeSpan(m_tmp_day - 11 - m_tmp_diff, 0, 0, 0);
      CDateTime newEnd = timestop + CDateTimeSpan(m_tmp_day - 11 - m_tmp_diff, 0, 0, 0);

      // add a day to end time if end time is before start time
      // TODO: this should be removed after separate end date control was added
      if (newEnd < newStart)
        newEnd += CDateTimeSpan(1, 0, 0, 0);

      tag->SetStartFromLocalTime(newStart);
      tag->SetEndFromLocalTime(newEnd);

      tag->m_bIsRepeating = false;
      tag->m_iWeekdays = 0;
    }
  }
  else if (settingId == SETTING_TMR_PRIORITY)
    tag->m_iPriority = static_cast<const CSettingInt*>(setting)->GetValue();
  else if (settingId == SETTING_TMR_LIFETIME)
    tag->m_iLifetime = static_cast<const CSettingInt*>(setting)->GetValue();
  else if (settingId == SETTING_TMR_FIRST_DAY)
  {
    m_tmp_iFirstDay = static_cast<const CSettingInt*>(setting)->GetValue();

    CDateTime newFirstDay;
    if (m_tmp_iFirstDay > 0)
      newFirstDay = CDateTime::GetCurrentDateTime() + CDateTimeSpan(m_tmp_iFirstDay - 1, 0, 0, 0);

    tag->SetFirstDayFromLocalTime(newFirstDay);
  }
  else if (settingId == SETTING_TMR_NAME)
    tag->m_strTitle = static_cast<const CSettingString*>(setting)->GetValue();
  else if (settingId == SETTING_TMR_DIR)
    tag->m_strDirectory = static_cast<const CSettingString*>(setting)->GetValue();

  tag->UpdateSummary();
}
Example #20
0
CPVRTimerInfoTagPtr CPVRTimerInfoTag::CreateFromEpg(const CEpgInfoTagPtr &tag)
{
    /* create a new timer */
    CPVRTimerInfoTagPtr newTag(new CPVRTimerInfoTag());
    if (!newTag)
    {
        CLog::Log(LOGERROR, "%s - couldn't create new timer", __FUNCTION__);
        return CPVRTimerInfoTagPtr();
    }

    /* check if a valid channel is set */
    CPVRChannelPtr channel = tag->ChannelTag();
    if (!channel)
    {
        CLog::Log(LOGERROR, "%s - no channel set", __FUNCTION__);
        return CPVRTimerInfoTagPtr();
    }

    /* check if the epg end date is in the future */
    if (tag->EndAsLocalTime() < CDateTime::GetCurrentDateTime())
    {
        CLog::Log(LOGERROR, "%s - end time is in the past", __FUNCTION__);
        return CPVRTimerInfoTagPtr();
    }

    /* set the timer data */
    CDateTime newStart = tag->StartAsUTC();
    CDateTime newEnd = tag->EndAsUTC();
    newTag->m_iClientIndex      = -1;
    newTag->m_strTitle          = tag->Title().empty() ? channel->ChannelName() : tag->Title();
    newTag->m_iChannelNumber    = channel->ChannelNumber();
    newTag->m_iClientChannelUid = channel->UniqueID();
    newTag->m_iClientId         = channel->ClientID();
    newTag->m_bIsRadio          = channel->IsRadio();
    newTag->m_iGenreType        = tag->GenreType();
    newTag->m_iGenreSubType     = tag->GenreSubType();
    newTag->m_channel           = channel;
    newTag->SetStartFromUTC(newStart);
    newTag->SetEndFromUTC(newEnd);

    if (tag->Plot().empty())
    {
        newTag->m_strSummary= StringUtils::Format("%s %s %s %s %s",
                              newTag->StartAsLocalTime().GetAsLocalizedDate().c_str(),
                              g_localizeStrings.Get(19159).c_str(),
                              newTag->StartAsLocalTime().GetAsLocalizedTime("", false).c_str(),
                              g_localizeStrings.Get(19160).c_str(),
                              newTag->EndAsLocalTime().GetAsLocalizedTime("", false).c_str());
    }
    else
    {
        newTag->m_strSummary = tag->Plot();
    }

    newTag->m_epgTag = g_EpgContainer.GetById(tag->EpgID())->GetTag(tag->StartAsUTC());

    /* unused only for reference */
    newTag->m_strFileNameAndPath = "pvr://timers/new";

    return newTag;
}
Example #21
0
void CPVRChannelGroup::SearchAndSetChannelIcons(bool bUpdateDb /* = false */)
{
  std::string iconPath = CServiceBroker::GetSettings().GetString(CSettings::SETTING_PVRMENU_ICONPATH);
  if (iconPath.empty())
    return;

  /* fetch files in icon path for fast lookup */
  CFileItemList fileItemList;
  XFILE::CDirectory::GetDirectory(iconPath, fileItemList, ".jpg|.png|.tbn");

  if (fileItemList.IsEmpty())
    return;

  CGUIDialogProgressBarHandle* dlgProgressHandle = g_PVRManager.ShowProgressDialog(g_localizeStrings.Get(19286)); // Searching for channel icons

  CSingleLock lock(m_critSection);

  /* create a map for fast lookup of normalized file base name */
  std::map<std::string, std::string> fileItemMap;
  const VECFILEITEMS &items = fileItemList.GetList();
  for(VECFILEITEMS::const_iterator it = items.begin(); it != items.end(); ++it)
  {
    std::string baseName = URIUtils::GetFileName((*it)->GetPath());
    URIUtils::RemoveExtension(baseName);
    StringUtils::ToLower(baseName);
    fileItemMap.insert(std::make_pair(baseName, (*it)->GetPath()));
  }

  int channelIndex = 0;
  CPVRChannelPtr channel;
  for(PVR_CHANNEL_GROUP_MEMBERS::const_iterator it = m_members.begin(); it != m_members.end(); ++it)
  {
    channel = it->second.channel;

    /* update progress dialog */
    if (dlgProgressHandle)
    {
      dlgProgressHandle->SetProgress(channelIndex++, m_members.size());
      dlgProgressHandle->SetText(channel->ChannelName());
    }

    /* skip if an icon is already set and exists */
    if (channel->IsIconExists())
      continue;

    /* reset icon before searching for a new one */
    channel->SetIconPath("");

    std::string strChannelUid = StringUtils::Format("%08d", channel->UniqueID());
    std::string strLegalClientChannelName = CUtil::MakeLegalFileName(channel->ClientChannelName());
    StringUtils::ToLower(strLegalClientChannelName);
    std::string strLegalChannelName = CUtil::MakeLegalFileName(channel->ChannelName());
    StringUtils::ToLower(strLegalChannelName);

    std::map<std::string, std::string>::iterator itItem;
    if ((itItem = fileItemMap.find(strLegalClientChannelName)) != fileItemMap.end() ||
        (itItem = fileItemMap.find(strLegalChannelName)) != fileItemMap.end() ||
        (itItem = fileItemMap.find(strChannelUid)) != fileItemMap.end())
    {
      channel->SetIconPath(itItem->second, g_advancedSettings.m_bPVRAutoScanIconsUserSet);
    }

    if (bUpdateDb)
      channel->Persist();

    //! @todo start channel icon scraper here if nothing was found
  }

  if (dlgProgressHandle)
    dlgProgressHandle->MarkFinished();
}
Example #22
0
CPVRTimerInfoTagPtr CPVRTimerInfoTag::CreateFromEpg(const CEpgInfoTagPtr &tag, bool bRepeating /* = false */)
{
  /* create a new timer */
  CPVRTimerInfoTagPtr newTag(new CPVRTimerInfoTag());

  /* check if a valid channel is set */
  CPVRChannelPtr channel = tag->ChannelTag();
  if (!channel)
  {
    CLog::Log(LOGERROR, "%s - no channel set", __FUNCTION__);
    return CPVRTimerInfoTagPtr();
  }

  /* check if the epg end date is in the future */
  if (tag->EndAsLocalTime() < CDateTime::GetCurrentDateTime())
  {
    CLog::Log(LOGERROR, "%s - end time is in the past", __FUNCTION__);
    return CPVRTimerInfoTagPtr();
  }

  /* set the timer data */
  CDateTime newStart = tag->StartAsUTC();
  CDateTime newEnd = tag->EndAsUTC();
  newTag->m_iClientIndex       = -1;
  newTag->m_iParentClientIndex = PVR_TIMER_NO_PARENT;
  newTag->m_strTitle           = tag->Title().empty() ? channel->ChannelName() : tag->Title();
  newTag->m_iChannelNumber     = channel->ChannelNumber();
  newTag->m_iClientChannelUid  = channel->UniqueID();
  newTag->m_iClientId          = channel->ClientID();
  newTag->m_bIsRadio           = channel->IsRadio();
  newTag->m_iGenreType         = tag->GenreType();
  newTag->m_iGenreSubType      = tag->GenreSubType();
  newTag->m_channel            = channel;
  newTag->SetStartFromUTC(newStart);
  newTag->SetEndFromUTC(newEnd);

  CPVRTimerTypePtr timerType;
  if (bRepeating)
  {
    // create repeating epg-based timer
    timerType = CPVRTimerType::CreateFromAttributes(
      PVR_TIMER_TYPE_IS_REPEATING,
      PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES, channel->ClientID());
  }
  if (!timerType)
  {
    // create one-shot epg-based timer
    timerType = CPVRTimerType::CreateFromAttributes(
      PVR_TIMER_TYPE_ATTRIBUTE_NONE,
      PVR_TIMER_TYPE_IS_REPEATING | PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES, channel->ClientID());
  }
  if (!timerType)
  {
    CLog::Log(LOGERROR, "%s - unable to create any epg-based timer type", __FUNCTION__);
    return CPVRTimerInfoTagPtr();
  }

  newTag->SetTimerType(timerType);
  newTag->UpdateSummary();
  newTag->m_epgTag = g_EpgContainer.GetById(tag->EpgID())->GetTag(tag->StartAsUTC());

  /* unused only for reference */
  newTag->m_strFileNameAndPath = CPVRTimersPath::PATH_NEW;

  return newTag;
}
Example #23
0
void CPVRChannelGroup::SearchAndSetChannelIcons(bool bUpdateDb /* = false */)
{
  std::string iconPath = CSettings::Get().GetString("pvrmenu.iconpath");
  if (iconPath.empty())
    return;

  CPVRDatabase *database = GetPVRDatabase();
  if (!database)
    return;

  /* fetch files in icon path for fast lookup */
  CFileItemList fileItemList;
  XFILE::CDirectory::GetDirectory(iconPath, fileItemList, ".jpg|.png|.tbn");

  if (fileItemList.IsEmpty())
    return;

  CGUIDialogExtendedProgressBar* dlgProgress = (CGUIDialogExtendedProgressBar*)g_windowManager.GetWindow(WINDOW_DIALOG_EXT_PROGRESS);
  CGUIDialogProgressBarHandle* dlgProgressHandle = dlgProgress ? dlgProgress->GetHandle(g_localizeStrings.Get(19287)) : NULL;

  CSingleLock lock(m_critSection);

  /* create a map for fast lookup of normalized file base name */
  std::map<std::string, std::string> fileItemMap;
  const VECFILEITEMS &items = fileItemList.GetList();
  for(VECFILEITEMS::const_iterator it = items.begin(); it != items.end(); ++it)
  {
    std::string baseName = URIUtils::GetFileName((*it)->GetPath());
    URIUtils::RemoveExtension(baseName);
    StringUtils::ToLower(baseName);
    fileItemMap.insert(std::make_pair(baseName, (*it)->GetPath()));
  }

  int channelIndex = 0;
  for(std::vector<PVRChannelGroupMember>::const_iterator it = m_members.begin(); it != m_members.end(); ++it)
  {
    CPVRChannelPtr channel = (*it).channel;

    /* update progress dialog */
    if (dlgProgressHandle)
    {
      dlgProgressHandle->SetProgress(channelIndex++, m_members.size());
      dlgProgressHandle->SetText(channel->ChannelName());
    }

    /* skip if an icon is already set and exists */
    if (channel->IsIconExists())
      continue;

    /* reset icon before searching for a new one */
    channel->SetIconPath("");

    std::string strChannelUid = StringUtils::Format("%08d", channel->UniqueID());
    std::string strLegalClientChannelName = CUtil::MakeLegalFileName(channel->ClientChannelName());
    StringUtils::ToLower(strLegalClientChannelName);
    std::string strLegalChannelName = CUtil::MakeLegalFileName(channel->ChannelName());
    StringUtils::ToLower(strLegalChannelName);

    std::map<std::string, std::string>::iterator itItem;
    if ((itItem = fileItemMap.find(strLegalClientChannelName)) != fileItemMap.end() ||
        (itItem = fileItemMap.find(strLegalChannelName)) != fileItemMap.end() ||
        (itItem = fileItemMap.find(strChannelUid)) != fileItemMap.end())
    {
      channel->SetIconPath(itItem->second, g_advancedSettings.m_bPVRAutoScanIconsUserSet);
    }

    if (bUpdateDb)
      channel->Persist();

    /* TODO: start channel icon scraper here if nothing was found */
  }

  if (dlgProgressHandle)
    dlgProgressHandle->MarkFinished();
}
Example #24
0
CPVRTimerInfoTag::CPVRTimerInfoTag(const PVR_TIMER &timer, const CPVRChannelPtr &channel, unsigned int iClientId) :
  m_strTitle(timer.strTitle),
  m_strEpgSearchString(timer.strEpgSearchString),
  m_bFullTextEpgSearch(timer.bFullTextEpgSearch),
  m_strDirectory(timer.strDirectory),
  m_state(timer.state),
  m_iClientId(iClientId),
  m_iClientIndex(timer.iClientIndex),
  m_iParentClientIndex(timer.iParentClientIndex),
  m_iClientChannelUid(channel ? channel->UniqueID() : (timer.iClientChannelUid > 0) ? timer.iClientChannelUid : PVR_CHANNEL_INVALID_UID),
  m_bStartAnyTime(timer.bStartAnyTime),
  m_bEndAnyTime(timer.bEndAnyTime),
  m_iPriority(timer.iPriority),
  m_iLifetime(timer.iLifetime),
  m_iMaxRecordings(timer.iMaxRecordings),
  m_iWeekdays(timer.iWeekdays),
  m_iPreventDupEpisodes(timer.iPreventDuplicateEpisodes),
  m_iRecordingGroup(timer.iRecordingGroup),
  m_strFileNameAndPath(StringUtils::Format("pvr://client%i/timers/%i", m_iClientId, m_iClientIndex)),
  m_iChannelNumber(channel ? g_PVRChannelGroups->GetGroupAll(channel->IsRadio())->GetChannelNumber(channel) : 0),
  m_bIsRadio(channel && channel->IsRadio()),
  m_iTimerId(0),
  m_channel(channel),
  m_iMarginStart(timer.iMarginStart),
  m_iMarginEnd(timer.iMarginEnd),
  m_StartTime(timer.startTime + g_advancedSettings.m_iPVRTimeCorrection),
  m_StopTime(timer.endTime + g_advancedSettings.m_iPVRTimeCorrection),
  m_FirstDay(timer.firstDay + g_advancedSettings.m_iPVRTimeCorrection),
  m_iEpgUid(timer.iEpgUid)
{
  if (m_iClientIndex == PVR_TIMER_NO_CLIENT_INDEX)
    CLog::Log(LOGERROR, "%s: invalid client index supplied by client %d (must be > 0)!", __FUNCTION__, m_iClientId);

  if (g_PVRClients->SupportsTimers(m_iClientId))
  {
    // begin compat section

    // Create timer type according to certain timer values already available in Isengard.
    // This is for migration only and does not make changes to the addons obsolete. Addons should
    // work and benefit from some UI changes (e.g. some of the timer settings dialog enhancements),
    // but all old problems/bugs due to static attributes and values will remain the same as in
    // Isengard. Also, new features (like epg search) are not available to addons automatically.
    // This code can be removed once all addons actually support the respective PVR Addon API version.
    if (timer.iTimerType == PVR_TIMER_TYPE_NONE)
    {
      // Create type according to certain timer values.
      unsigned int iMustHave    = PVR_TIMER_TYPE_ATTRIBUTE_NONE;
      unsigned int iMustNotHave = PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES;

      if (timer.iEpgUid == PVR_TIMER_NO_EPG_UID && timer.iWeekdays != PVR_WEEKDAY_NONE)
        iMustHave |= PVR_TIMER_TYPE_IS_REPEATING;
      else
        iMustNotHave |= PVR_TIMER_TYPE_IS_REPEATING;

      if (timer.iEpgUid == PVR_TIMER_NO_EPG_UID)
        iMustHave |= PVR_TIMER_TYPE_IS_MANUAL;
      else
        iMustNotHave |= PVR_TIMER_TYPE_IS_MANUAL;

      CPVRTimerTypePtr type(CPVRTimerType::CreateFromAttributes(iMustHave, iMustNotHave, m_iClientId));

      if (type)
        SetTimerType(type);
    }
    // end compat section
    else
    {
      SetTimerType(CPVRTimerType::CreateFromIds(timer.iTimerType, m_iClientId));
    }

    if (!m_timerType)
      CLog::Log(LOGERROR, "%s: no timer type, although timers are supported by client %d!", __FUNCTION__, m_iClientId);
    else if (m_iEpgUid == EPG_TAG_INVALID_UID && m_timerType->IsEpgBasedOnetime())
      CLog::Log(LOGERROR, "%s: no epg tag given for epg based timer type (%d)!", __FUNCTION__, m_timerType->GetTypeId());
  }

  ResetChildState();
  UpdateSummary();
  UpdateEpgInfoTag();
}
Example #25
0
CPVRTimerInfoTag::CPVRTimerInfoTag(const PVR_TIMER &timer, const CPVRChannelPtr &channel, unsigned int iClientId) :
  m_strTitle(timer.strTitle),
  m_strEpgSearchString(timer.strEpgSearchString),
  m_bFullTextEpgSearch(timer.bFullTextEpgSearch),
  m_strDirectory(timer.strDirectory)
{
  m_iClientId           = iClientId;
  m_iClientIndex        = timer.iClientIndex;
  m_iParentClientIndex  = timer.iParentClientIndex;
  m_iClientChannelUid   = channel ? channel->UniqueID() : (timer.iClientChannelUid > 0) ? timer.iClientChannelUid : PVR_INVALID_CHANNEL_UID;
  m_iChannelNumber      = channel ? g_PVRChannelGroups->GetGroupAll(channel->IsRadio())->GetChannelNumber(channel) : 0;
  m_StartTime           = timer.startTime + g_advancedSettings.m_iPVRTimeCorrection;
  m_StopTime            = timer.endTime + g_advancedSettings.m_iPVRTimeCorrection;
  m_iPreventDupEpisodes = timer.iPreventDuplicateEpisodes;
  m_iRecordingGroup     = timer.iRecordingGroup;
  m_FirstDay            = timer.firstDay + g_advancedSettings.m_iPVRTimeCorrection;
  m_iWeekdays           = timer.iWeekdays;
  m_iPriority           = timer.iPriority;
  m_iLifetime           = timer.iLifetime;
  m_iMarginStart        = timer.iMarginStart;
  m_iMarginEnd          = timer.iMarginEnd;
  m_genre               = StringUtils::Split(CEpg::ConvertGenreIdToString(timer.iGenreType, timer.iGenreSubType), g_advancedSettings.m_videoItemSeparator);
  m_iGenreType          = timer.iGenreType;
  m_iGenreSubType       = timer.iGenreSubType;
  m_channel             = channel;
  m_bIsRadio            = channel && channel->IsRadio();
  m_state               = timer.state;
  m_strFileNameAndPath  = StringUtils::Format("pvr://client%i/timers/%i", m_iClientId, m_iClientIndex);
  m_iTimerId            = 0;

  if (g_PVRClients->SupportsTimers(m_iClientId))
  {
    // begin compat section

    // Create timer type according to certain timer values already available in Isengard.
    // This is for migration only and does not make changes to the addons obsolete. Addons should
    // work and benefit from some UI changes (e.g. some of the timer settings dialog enhancements),
    // but all old problems/bugs due to static attributes and values will remain the same as in
    // Isengard. Also, new features (like epg search) are not available to addons automatically.
    // This code can be removed once all addons actually support the respective PVR Addon API version.
    if (timer.iTimerType == PVR_TIMER_TYPE_NONE)
    {
      // Create type according to certain timer values.
      unsigned int iMustHave    = PVR_TIMER_TYPE_ATTRIBUTE_NONE;
      unsigned int iMustNotHave = PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES;

      if (timer.iWeekdays != PVR_WEEKDAY_NONE)
        iMustHave |= PVR_TIMER_TYPE_IS_REPEATING;
      else
        iMustNotHave |= PVR_TIMER_TYPE_IS_REPEATING;

      if (timer.iEpgUid == 0)
        iMustHave |= PVR_TIMER_TYPE_IS_MANUAL;
      else
        iMustNotHave |= PVR_TIMER_TYPE_IS_MANUAL;

      CPVRTimerTypePtr type(CPVRTimerType::CreateFromAttributes(iMustHave, iMustNotHave, m_iClientId));

      if (type)
        SetTimerType(type);
    }
    // end compat section
    else
    {
      SetTimerType(CPVRTimerType::CreateFromIds(timer.iTimerType, m_iClientId));
    }

    if (!m_timerType)
      CLog::Log(LOGERROR, "%s: no timer type, although timers are supported by client %d!", __FUNCTION__, m_iClientId);
  }

  UpdateSummary();
}