1 /*
2  *  Copyright (C) 2012-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "PVRChannel.h"
10 
11 #include "ServiceBroker.h"
12 #include "XBDateTime.h"
13 #include "guilib/LocalizeStrings.h"
14 #include "pvr/PVRDatabase.h"
15 #include "pvr/PVRManager.h"
16 #include "pvr/addons/PVRClient.h"
17 #include "pvr/channels/PVRChannelsPath.h"
18 #include "pvr/epg/Epg.h"
19 #include "pvr/epg/EpgChannelData.h"
20 #include "pvr/epg/EpgContainer.h"
21 #include "pvr/epg/EpgInfoTag.h"
22 #include "threads/SingleLock.h"
23 #include "utils/StringUtils.h"
24 #include "utils/Variant.h"
25 #include "utils/log.h"
26 
27 #include <memory>
28 #include <string>
29 
30 using namespace PVR;
31 
operator ==(const CPVRChannel & right) const32 bool CPVRChannel::operator==(const CPVRChannel& right) const
33 {
34   return (m_bIsRadio == right.m_bIsRadio &&
35           m_iUniqueId == right.m_iUniqueId &&
36           m_iClientId == right.m_iClientId);
37 }
38 
operator !=(const CPVRChannel & right) const39 bool CPVRChannel::operator!=(const CPVRChannel& right) const
40 {
41   return !(*this == right);
42 }
43 
CPVRChannel()44 CPVRChannel::CPVRChannel()
45 {
46   UpdateEncryptionName();
47 }
48 
CPVRChannel(bool bRadio)49 CPVRChannel::CPVRChannel(bool bRadio)
50   : m_bIsRadio(bRadio)
51 {
52   UpdateEncryptionName();
53 }
54 
CPVRChannel(const PVR_CHANNEL & channel,unsigned int iClientId)55 CPVRChannel::CPVRChannel(const PVR_CHANNEL& channel, unsigned int iClientId)
56   : m_bIsRadio(channel.bIsRadio),
57     m_bIsHidden(channel.bIsHidden),
58     m_strIconPath(channel.strIconPath),
59     m_strChannelName(channel.strChannelName),
60     m_bHasArchive(channel.bHasArchive),
61     m_bEPGEnabled(!channel.bIsHidden),
62     m_iUniqueId(channel.iUniqueId),
63     m_iClientId(iClientId),
64     m_clientChannelNumber(channel.iChannelNumber, channel.iSubChannelNumber),
65     m_strClientChannelName(channel.strChannelName),
66     m_strMimeType(channel.strMimeType),
67     m_iClientEncryptionSystem(channel.iEncryptionSystem)
68 {
69   if (m_strChannelName.empty())
70     m_strChannelName = StringUtils::Format("%s %d", g_localizeStrings.Get(19029).c_str(), m_iUniqueId);
71 
72   UpdateEncryptionName();
73 }
74 
~CPVRChannel()75 CPVRChannel::~CPVRChannel()
76 {
77   ResetEPG();
78 }
79 
Serialize(CVariant & value) const80 void CPVRChannel::Serialize(CVariant& value) const
81 {
82   value["channelid"] = m_iChannelId;
83   value["channeltype"] = m_bIsRadio ? "radio" : "tv";
84   value["hidden"] = m_bIsHidden;
85   value["locked"] = m_bIsLocked;
86   value["icon"] = m_strIconPath;
87   value["channel"]  = m_strChannelName;
88   value["uniqueid"]  = m_iUniqueId;
89   CDateTime lastPlayed(m_iLastWatched);
90   value["lastplayed"] = lastPlayed.IsValid() ? lastPlayed.GetAsDBDate() : "";
91   value["channelnumber"] = m_channelNumber.GetChannelNumber();
92   value["subchannelnumber"] = m_channelNumber.GetSubChannelNumber();
93 
94   std::shared_ptr<CPVREpgInfoTag> epg = GetEPGNow();
95   if (epg)
96   {
97     // add the properties of the current EPG item to the main object
98     epg->Serialize(value);
99     // and add an extra sub-object with only the current EPG details
100     epg->Serialize(value["broadcastnow"]);
101   }
102 
103   epg = GetEPGNext();
104   if (epg)
105     epg->Serialize(value["broadcastnext"]);
106 
107   value["hasarchive"] = m_bHasArchive;
108   value["clientid"] = m_iClientId;
109 }
110 
QueueDelete()111 bool CPVRChannel::QueueDelete()
112 {
113   bool bReturn = false;
114   const std::shared_ptr<CPVRDatabase> database = CServiceBroker::GetPVRManager().GetTVDatabase();
115   if (!database)
116     return bReturn;
117 
118   const std::shared_ptr<CPVREpg> epg = GetEPG();
119   if (epg)
120     ResetEPG();
121 
122   bReturn = database->QueueDeleteQuery(*this);
123   return bReturn;
124 }
125 
GetEPG() const126 std::shared_ptr<CPVREpg> CPVRChannel::GetEPG() const
127 {
128   const_cast<CPVRChannel*>(this)->CreateEPG();
129 
130   CSingleLock lock(m_critSection);
131   if (!m_bIsHidden && m_bEPGEnabled)
132     return m_epg;
133 
134   return {};
135 }
136 
CreateEPG()137 bool CPVRChannel::CreateEPG()
138 {
139   CSingleLock lock(m_critSection);
140   if (!m_epg)
141   {
142     m_epg = CServiceBroker::GetPVRManager().EpgContainer().CreateChannelEpg(m_iEpgId,
143                                                                             m_strEPGScraper,
144                                                                             std::make_shared<CPVREpgChannelData>(*this));
145     if (m_epg)
146     {
147       if (m_epg->EpgID() != m_iEpgId)
148       {
149         m_iEpgId = m_epg->EpgID();
150         m_bChanged = true;
151       }
152 
153       // Subscribe for EPG delete event
154       m_epg->Events().Subscribe(this, &CPVRChannel::Notify);
155       return true;
156     }
157   }
158   return false;
159 }
160 
Notify(const PVREvent & event)161 void CPVRChannel::Notify(const PVREvent& event)
162 {
163   if (event == PVREvent::EpgDeleted)
164   {
165     ResetEPG();
166   }
167 }
168 
ResetEPG()169 void CPVRChannel::ResetEPG()
170 {
171   std::shared_ptr<CPVREpg> epgToUnsubscribe;
172   {
173     CSingleLock lock(m_critSection);
174     if (m_epg)
175     {
176       epgToUnsubscribe = m_epg;
177       m_epg.reset();
178     }
179   }
180 
181   if (epgToUnsubscribe)
182     epgToUnsubscribe->Events().Unsubscribe(this);
183 }
184 
UpdateFromClient(const std::shared_ptr<CPVRChannel> & channel)185 bool CPVRChannel::UpdateFromClient(const std::shared_ptr<CPVRChannel>& channel)
186 {
187   SetClientID(channel->ClientID());
188 
189   CSingleLock lock(m_critSection);
190 
191   if (m_clientChannelNumber != channel->m_clientChannelNumber ||
192       m_strMimeType != channel->MimeType() ||
193       m_iClientEncryptionSystem != channel->EncryptionSystem() ||
194       m_strClientChannelName != channel->ClientChannelName() ||
195       m_bHasArchive != channel->HasArchive())
196   {
197     m_clientChannelNumber = channel->m_clientChannelNumber;
198     m_strMimeType = channel->MimeType();
199     m_iClientEncryptionSystem = channel->EncryptionSystem();
200     m_strClientChannelName = channel->ClientChannelName();
201     m_bHasArchive = channel->HasArchive();
202 
203     UpdateEncryptionName();
204 
205     m_bChanged = true;
206   }
207 
208   // only update the channel name and icon if the user hasn't changed them manually
209   if (m_strChannelName.empty() || !IsUserSetName())
210     SetChannelName(channel->ClientChannelName());
211   if (m_strIconPath.empty() || !IsUserSetIcon())
212     SetIconPath(channel->IconPath());
213 
214   return m_bChanged;
215 }
216 
Persist()217 bool CPVRChannel::Persist()
218 {
219   {
220     // not changed
221     CSingleLock lock(m_critSection);
222     if (!m_bChanged && m_iChannelId > 0)
223       return true;
224   }
225 
226   const std::shared_ptr<CPVRDatabase> database = CServiceBroker::GetPVRManager().GetTVDatabase();
227   if (database)
228   {
229     bool bReturn = database->Persist(*this, true);
230 
231     CSingleLock lock(m_critSection);
232     m_bChanged = !bReturn;
233     return bReturn;
234   }
235 
236   return false;
237 }
238 
SetChannelID(int iChannelId)239 bool CPVRChannel::SetChannelID(int iChannelId)
240 {
241   CSingleLock lock(m_critSection);
242   if (m_iChannelId != iChannelId)
243   {
244     m_iChannelId = iChannelId;
245 
246     const std::shared_ptr<CPVREpg> epg = GetEPG();
247     if (epg)
248       epg->GetChannelData()->SetChannelId(m_iChannelId);
249 
250     m_bChanged = true;
251     return true;
252   }
253 
254   return false;
255 }
256 
ChannelNumber() const257 const CPVRChannelNumber& CPVRChannel::ChannelNumber() const
258 {
259   CSingleLock lock(m_critSection);
260   return m_channelNumber;
261 }
262 
SetHidden(bool bIsHidden)263 bool CPVRChannel::SetHidden(bool bIsHidden)
264 {
265   CSingleLock lock(m_critSection);
266 
267   if (m_bIsHidden != bIsHidden)
268   {
269     m_bIsHidden = bIsHidden;
270     m_bEPGEnabled = !bIsHidden;
271 
272     const std::shared_ptr<CPVREpg> epg = GetEPG();
273     if (epg)
274     {
275       epg->GetChannelData()->SetHidden(m_bIsHidden);
276       epg->GetChannelData()->SetEPGEnabled(m_bEPGEnabled);
277     }
278 
279     m_bChanged = true;
280     return true;
281   }
282 
283   return false;
284 }
285 
SetLocked(bool bIsLocked)286 bool CPVRChannel::SetLocked(bool bIsLocked)
287 {
288   CSingleLock lock(m_critSection);
289 
290   if (m_bIsLocked != bIsLocked)
291   {
292     m_bIsLocked = bIsLocked;
293 
294     const std::shared_ptr<CPVREpg> epg = GetEPG();
295     if (epg)
296       epg->GetChannelData()->SetLocked(m_bIsLocked);
297 
298     m_bChanged = true;
299     return true;
300   }
301 
302   return false;
303 }
304 
GetRadioRDSInfoTag() const305 std::shared_ptr<CPVRRadioRDSInfoTag> CPVRChannel::GetRadioRDSInfoTag() const
306 {
307   CSingleLock lock(m_critSection);
308   return m_rdsTag;
309 }
310 
SetRadioRDSInfoTag(const std::shared_ptr<CPVRRadioRDSInfoTag> & tag)311 void CPVRChannel::SetRadioRDSInfoTag(const std::shared_ptr<CPVRRadioRDSInfoTag>& tag)
312 {
313   CSingleLock lock(m_critSection);
314   m_rdsTag = tag;
315 }
316 
HasArchive() const317 bool CPVRChannel::HasArchive() const
318 {
319   CSingleLock lock(m_critSection);
320   return m_bHasArchive;
321 }
322 
SetIconPath(const std::string & strIconPath,bool bIsUserSetIcon)323 bool CPVRChannel::SetIconPath(const std::string& strIconPath, bool bIsUserSetIcon /* = false */)
324 {
325   CSingleLock lock(m_critSection);
326   if (m_strIconPath != strIconPath)
327   {
328     m_strIconPath = StringUtils::Format("%s", strIconPath.c_str());
329 
330     m_bChanged = true;
331     m_bIsUserSetIcon = bIsUserSetIcon && !m_strIconPath.empty();
332     return true;
333   }
334 
335   return false;
336 }
337 
SetChannelName(const std::string & strChannelName,bool bIsUserSetName)338 bool CPVRChannel::SetChannelName(const std::string& strChannelName, bool bIsUserSetName /*= false*/)
339 {
340   std::string strName(strChannelName);
341 
342   if (strName.empty())
343     strName = StringUtils::Format(g_localizeStrings.Get(19085).c_str(), m_clientChannelNumber.FormattedChannelNumber().c_str());
344 
345   CSingleLock lock(m_critSection);
346   if (m_strChannelName != strName)
347   {
348     m_strChannelName = strName;
349     m_bIsUserSetName = bIsUserSetName;
350 
351     /* if the user changes the name manually to an empty string we reset the
352        flag and use the name from the client instead */
353     if (bIsUserSetName && strChannelName.empty())
354     {
355       m_bIsUserSetName = false;
356       m_strChannelName = ClientChannelName();
357     }
358 
359     const std::shared_ptr<CPVREpg> epg = GetEPG();
360     if (epg)
361       epg->GetChannelData()->SetChannelName(m_strChannelName);
362 
363     m_bChanged = true;
364     return true;
365   }
366 
367   return false;
368 }
369 
SetLastWatched(time_t iLastWatched)370 bool CPVRChannel::SetLastWatched(time_t iLastWatched)
371 {
372   {
373     CSingleLock lock(m_critSection);
374     m_iLastWatched = iLastWatched;
375   }
376 
377   const std::shared_ptr<CPVRDatabase> database = CServiceBroker::GetPVRManager().GetTVDatabase();
378   if (database)
379     return database->UpdateLastWatched(*this);
380 
381   return false;
382 }
383 
IsEmpty() const384 bool CPVRChannel::IsEmpty() const
385 {
386   CSingleLock lock(m_critSection);
387   return m_strFileNameAndPath.empty();
388 }
389 
390 /********** Client related channel methods **********/
391 
SetClientID(int iClientId)392 bool CPVRChannel::SetClientID(int iClientId)
393 {
394   CSingleLock lock(m_critSection);
395 
396   if (m_iClientId != iClientId)
397   {
398     m_iClientId = iClientId;
399     m_bChanged = true;
400     return true;
401   }
402 
403   return false;
404 }
405 
UpdatePath(const std::string & channelGroup)406 void CPVRChannel::UpdatePath(const std::string& channelGroup)
407 {
408   const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(m_iClientId);
409   if (client)
410   {
411     CSingleLock lock(m_critSection);
412     const std::string strFileNameAndPath = CPVRChannelsPath(m_bIsRadio, channelGroup, client->ID(), m_iUniqueId);
413     if (m_strFileNameAndPath != strFileNameAndPath)
414       m_strFileNameAndPath = strFileNameAndPath;
415   }
416 }
417 
GetEncryptionName(int iCaid)418 std::string CPVRChannel::GetEncryptionName(int iCaid)
419 {
420   // http://www.dvb.org/index.php?id=174
421   // http://en.wikipedia.org/wiki/Conditional_access_system
422   std::string strName(g_localizeStrings.Get(13205)); /* Unknown */
423 
424   if (     iCaid == 0x0000)
425     strName = g_localizeStrings.Get(19013); /* Free To Air */
426   else if (iCaid >= 0x0001 &&
427            iCaid <= 0x009F)
428     strName = g_localizeStrings.Get(19014); /* Fixed */
429   else if (iCaid >= 0x00A0 &&
430            iCaid<= 0x00A1)
431     strName = g_localizeStrings.Get(338); /* Analog */
432   else if (iCaid >= 0x00A2 &&
433            iCaid <= 0x00FF)
434     strName = g_localizeStrings.Get(19014); /* Fixed */
435   else if (iCaid >= 0x0100 &&
436            iCaid <= 0x01FF)
437     strName = "SECA Mediaguard";
438   else if (iCaid == 0x0464)
439     strName = "EuroDec";
440   else if (iCaid >= 0x0500 &&
441            iCaid <= 0x05FF)
442     strName = "Viaccess";
443   else if (iCaid >= 0x0600 &&
444            iCaid <= 0x06FF)
445     strName = "Irdeto";
446   else if (iCaid >= 0x0900 &&
447            iCaid <= 0x09FF)
448     strName = "NDS Videoguard";
449   else if (iCaid >= 0x0B00 &&
450            iCaid <= 0x0BFF)
451     strName = "Conax";
452   else if (iCaid >= 0x0D00 &&
453            iCaid <= 0x0DFF)
454     strName = "CryptoWorks";
455   else if (iCaid >= 0x0E00 &&
456            iCaid <= 0x0EFF)
457     strName = "PowerVu";
458   else if (iCaid == 0x1000)
459     strName = "RAS";
460   else if (iCaid >= 0x1200 &&
461            iCaid <= 0x12FF)
462     strName = "NagraVision";
463   else if (iCaid >= 0x1700 &&
464            iCaid <= 0x17FF)
465     strName = "BetaCrypt";
466   else if (iCaid >= 0x1800 &&
467            iCaid <= 0x18FF)
468     strName = "NagraVision";
469   else if (iCaid == 0x22F0)
470     strName = "Codicrypt";
471   else if (iCaid == 0x2600)
472     strName = "BISS";
473   else if (iCaid == 0x4347)
474     strName = "CryptOn";
475   else if (iCaid == 0x4800)
476     strName = "Accessgate";
477   else if (iCaid == 0x4900)
478     strName = "China Crypt";
479   else if (iCaid == 0x4A10)
480     strName = "EasyCas";
481   else if (iCaid == 0x4A20)
482     strName = "AlphaCrypt";
483   else if (iCaid == 0x4A70)
484     strName = "DreamCrypt";
485   else if (iCaid == 0x4A60)
486     strName = "SkyCrypt";
487   else if (iCaid == 0x4A61)
488     strName = "Neotioncrypt";
489   else if (iCaid == 0x4A62)
490     strName = "SkyCrypt";
491   else if (iCaid == 0x4A63)
492     strName = "Neotion SHL";
493   else if (iCaid >= 0x4A64 &&
494            iCaid <= 0x4A6F)
495     strName = "SkyCrypt";
496   else if (iCaid == 0x4A80)
497     strName = "ThalesCrypt";
498   else if (iCaid == 0x4AA1)
499     strName = "KeyFly";
500   else if (iCaid == 0x4ABF)
501     strName = "DG-Crypt";
502   else if (iCaid >= 0x4AD0 &&
503            iCaid <= 0x4AD1)
504     strName = "X-Crypt";
505   else if (iCaid == 0x4AD4)
506     strName = "OmniCrypt";
507   else if (iCaid == 0x4AE0)
508     strName = "RossCrypt";
509   else if (iCaid == 0x5500)
510     strName = "Z-Crypt";
511   else if (iCaid == 0x5501)
512     strName = "Griffin";
513   else if (iCaid == 0x5601)
514     strName = "Verimatrix";
515 
516   if (iCaid >= 0)
517     strName += StringUtils::Format(" (%04X)", iCaid);
518 
519   return strName;
520 }
521 
UpdateEncryptionName()522 void CPVRChannel::UpdateEncryptionName()
523 {
524   CSingleLock lock(m_critSection);
525   m_strClientEncryptionName = GetEncryptionName(m_iClientEncryptionSystem);
526 }
527 
528 /********** EPG methods **********/
529 
GetEpgTags() const530 std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVRChannel::GetEpgTags() const
531 {
532   const std::shared_ptr<CPVREpg> epg = GetEPG();
533   if (!epg)
534   {
535     CLog::LogFC(LOGDEBUG, LOGPVR, "Cannot get EPG for channel '{}'", m_strChannelName);
536     return {};
537   }
538 
539   return epg->GetTags();
540 }
541 
GetEPGTimeline(const CDateTime & timelineStart,const CDateTime & timelineEnd,const CDateTime & minEventEnd,const CDateTime & maxEventStart) const542 std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVRChannel::GetEPGTimeline(
543     const CDateTime& timelineStart,
544     const CDateTime& timelineEnd,
545     const CDateTime& minEventEnd,
546     const CDateTime& maxEventStart) const
547 {
548   const std::shared_ptr<CPVREpg> epg = GetEPG();
549   if (epg)
550   {
551     return epg->GetTimeline(timelineStart, timelineEnd, minEventEnd, maxEventStart);
552   }
553   else
554   {
555     // return single gap tag spanning whole timeline
556     return std::vector<std::shared_ptr<CPVREpgInfoTag>>{
557         CreateEPGGapTag(timelineStart, timelineEnd)};
558   }
559 }
560 
CreateEPGGapTag(const CDateTime & start,const CDateTime & end) const561 std::shared_ptr<CPVREpgInfoTag> CPVRChannel::CreateEPGGapTag(const CDateTime& start,
562                                                              const CDateTime& end) const
563 {
564   const std::shared_ptr<CPVREpg> epg = GetEPG();
565   if (epg)
566     return std::make_shared<CPVREpgInfoTag>(epg->GetChannelData(), epg->EpgID(), start, end, true);
567   else
568     return std::make_shared<CPVREpgInfoTag>(std::make_shared<CPVREpgChannelData>(*this), -1, start,
569                                             end, true);
570 }
571 
ClearEPG() const572 bool CPVRChannel::ClearEPG() const
573 {
574   const std::shared_ptr<CPVREpg> epg = GetEPG();
575   if (epg)
576     epg->Clear();
577 
578   return true;
579 }
580 
GetEPGNow() const581 std::shared_ptr<CPVREpgInfoTag> CPVRChannel::GetEPGNow() const
582 {
583   std::shared_ptr<CPVREpgInfoTag> tag;
584   const std::shared_ptr<CPVREpg> epg = GetEPG();
585   if (epg)
586     tag = epg->GetTagNow();
587 
588   return tag;
589 }
590 
GetEPGNext() const591 std::shared_ptr<CPVREpgInfoTag> CPVRChannel::GetEPGNext() const
592 {
593   std::shared_ptr<CPVREpgInfoTag> tag;
594   const std::shared_ptr<CPVREpg> epg = GetEPG();
595   if (epg)
596     tag = epg->GetTagNext();
597 
598   return tag;
599 }
600 
GetEPGPrevious() const601 std::shared_ptr<CPVREpgInfoTag> CPVRChannel::GetEPGPrevious() const
602 {
603   std::shared_ptr<CPVREpgInfoTag> tag;
604   const std::shared_ptr<CPVREpg> epg = GetEPG();
605   if (epg)
606     tag = epg->GetTagPrevious();
607 
608   return tag;
609 }
610 
SetEPGEnabled(bool bEPGEnabled)611 bool CPVRChannel::SetEPGEnabled(bool bEPGEnabled)
612 {
613   CSingleLock lock(m_critSection);
614 
615   if (m_bEPGEnabled != bEPGEnabled)
616   {
617     m_bEPGEnabled = bEPGEnabled;
618 
619     const std::shared_ptr<CPVREpg> epg = GetEPG();
620     if (epg)
621       epg->GetChannelData()->SetEPGEnabled(m_bEPGEnabled);
622 
623     m_bChanged = true;
624 
625     /* clear the previous EPG entries if needed */
626     if (!m_bEPGEnabled && m_epg)
627       ClearEPG();
628 
629     return true;
630   }
631 
632   return false;
633 }
634 
SetEPGScraper(const std::string & strScraper)635 bool CPVRChannel::SetEPGScraper(const std::string& strScraper)
636 {
637   CSingleLock lock(m_critSection);
638 
639   if (m_strEPGScraper != strScraper)
640   {
641     bool bCleanEPG = !m_strEPGScraper.empty() || strScraper.empty();
642 
643     m_strEPGScraper = StringUtils::Format("%s", strScraper.c_str());
644     m_bChanged = true;
645 
646     /* clear the previous EPG entries if needed */
647     if (bCleanEPG && m_bEPGEnabled && m_epg)
648       ClearEPG();
649 
650     return true;
651   }
652 
653   return false;
654 }
655 
SetChannelNumber(const CPVRChannelNumber & channelNumber)656 void CPVRChannel::SetChannelNumber(const CPVRChannelNumber& channelNumber)
657 {
658   CSingleLock lock(m_critSection);
659   m_channelNumber = channelNumber;
660 }
661 
SetClientChannelNumber(const CPVRChannelNumber & clientChannelNumber)662 void CPVRChannel::SetClientChannelNumber(const CPVRChannelNumber& clientChannelNumber)
663 {
664   CSingleLock lock(m_critSection);
665   m_clientChannelNumber = clientChannelNumber;
666 }
667 
ToSortable(SortItem & sortable,Field field) const668 void CPVRChannel::ToSortable(SortItem& sortable, Field field) const
669 {
670   CSingleLock lock(m_critSection);
671   if (field == FieldChannelName)
672     sortable[FieldChannelName] = m_strChannelName;
673   else if (field == FieldChannelNumber)
674     sortable[FieldChannelNumber] = m_channelNumber.SortableChannelNumber();
675   else if (field == FieldClientChannelOrder)
676   {
677     if (m_iOrder)
678       sortable[FieldClientChannelOrder] = m_iOrder;
679     else
680       sortable[FieldClientChannelOrder] = m_clientChannelNumber.SortableChannelNumber();
681   }
682   else if (field == FieldLastPlayed)
683   {
684     const CDateTime lastWatched(m_iLastWatched);
685     sortable[FieldLastPlayed] = lastWatched.IsValid() ? lastWatched.GetAsDBDateTime() : StringUtils::Empty;
686   }
687 }
688 
ChannelID() const689 int CPVRChannel::ChannelID() const
690 {
691   CSingleLock lock(m_critSection);
692   return m_iChannelId;
693 }
694 
IsNew() const695 bool CPVRChannel::IsNew() const
696 {
697   CSingleLock lock(m_critSection);
698   return m_iChannelId <= 0;
699 }
700 
IsHidden() const701 bool CPVRChannel::IsHidden() const
702 {
703   CSingleLock lock(m_critSection);
704   return m_bIsHidden;
705 }
706 
IsLocked() const707 bool CPVRChannel::IsLocked() const
708 {
709   CSingleLock lock(m_critSection);
710   return m_bIsLocked;
711 }
712 
IconPath() const713 std::string CPVRChannel::IconPath() const
714 {
715   CSingleLock lock(m_critSection);
716   return m_strIconPath;
717 }
718 
IsUserSetIcon() const719 bool CPVRChannel::IsUserSetIcon() const
720 {
721   CSingleLock lock(m_critSection);
722   return m_bIsUserSetIcon;
723 }
724 
IsUserSetName() const725 bool CPVRChannel::IsUserSetName() const
726 {
727   CSingleLock lock(m_critSection);
728   return m_bIsUserSetName;
729 }
730 
ChannelName() const731 std::string CPVRChannel::ChannelName() const
732 {
733   CSingleLock lock(m_critSection);
734   return m_strChannelName;
735 }
736 
LastWatched() const737 time_t CPVRChannel::LastWatched() const
738 {
739   CSingleLock lock(m_critSection);
740   return m_iLastWatched;
741 }
742 
IsChanged() const743 bool CPVRChannel::IsChanged() const
744 {
745   CSingleLock lock(m_critSection);
746   return m_bChanged;
747 }
748 
Persisted()749 void CPVRChannel::Persisted()
750 {
751   CSingleLock lock(m_critSection);
752   m_bChanged = false;
753 }
754 
UniqueID() const755 int CPVRChannel::UniqueID() const
756 {
757   return m_iUniqueId;
758 }
759 
ClientID() const760 int CPVRChannel::ClientID() const
761 {
762   CSingleLock lock(m_critSection);
763   return m_iClientId;
764 }
765 
ClientChannelNumber() const766 const CPVRChannelNumber& CPVRChannel::ClientChannelNumber() const
767 {
768   CSingleLock lock(m_critSection);
769   return m_clientChannelNumber;
770 }
771 
ClientChannelName() const772 std::string CPVRChannel::ClientChannelName() const
773 {
774   CSingleLock lock(m_critSection);
775   return m_strClientChannelName;
776 }
777 
MimeType() const778 std::string CPVRChannel::MimeType() const
779 {
780   CSingleLock lock(m_critSection);
781   return m_strMimeType;
782 }
783 
Path() const784 std::string CPVRChannel::Path() const
785 {
786   CSingleLock lock(m_critSection);
787   return m_strFileNameAndPath;
788 }
789 
IsEncrypted() const790 bool CPVRChannel::IsEncrypted() const
791 {
792   CSingleLock lock(m_critSection);
793   return m_iClientEncryptionSystem > 0;
794 }
795 
EncryptionSystem() const796 int CPVRChannel::EncryptionSystem() const
797 {
798   CSingleLock lock(m_critSection);
799   return m_iClientEncryptionSystem;
800 }
801 
EncryptionName() const802 std::string CPVRChannel::EncryptionName() const
803 {
804   CSingleLock lock(m_critSection);
805   return m_strClientEncryptionName;
806 }
807 
EpgID() const808 int CPVRChannel::EpgID() const
809 {
810   CSingleLock lock(m_critSection);
811   return m_iEpgId;
812 }
813 
EPGEnabled() const814 bool CPVRChannel::EPGEnabled() const
815 {
816   CSingleLock lock(m_critSection);
817   return m_bEPGEnabled;
818 }
819 
EPGScraper() const820 std::string CPVRChannel::EPGScraper() const
821 {
822   CSingleLock lock(m_critSection);
823   return m_strEPGScraper;
824 }
825 
CanRecord() const826 bool CPVRChannel::CanRecord() const
827 {
828   const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(m_iClientId);
829   return client && client->GetClientCapabilities().SupportsRecordings();
830 }
831 
SetClientOrder(int iOrder)832 void CPVRChannel::SetClientOrder(int iOrder)
833 {
834   CSingleLock lock(m_critSection);
835   m_iOrder = iOrder;
836 }
837