[release] version bump to 13.0 beta1
[vuplus_xbmc] / xbmc / epg / EpgInfoTag.cpp
1 /*
2  *      Copyright (C) 2012-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "guilib/LocalizeStrings.h"
22 #include "Epg.h"
23 #include "EpgInfoTag.h"
24 #include "EpgContainer.h"
25 #include "EpgDatabase.h"
26 #include "pvr/channels/PVRChannelGroupsContainer.h"
27 #include "pvr/timers/PVRTimers.h"
28 #include "pvr/PVRManager.h"
29 #include "settings/AdvancedSettings.h"
30 #include "settings/Settings.h"
31 #include "utils/log.h"
32 #include "utils/Variant.h"
33 #include "addons/include/xbmc_pvr_types.h"
34
35 using namespace std;
36 using namespace EPG;
37 using namespace PVR;
38
39 CEpgInfoTag::CEpgInfoTag(void) :
40     m_bNotify(false),
41     m_bChanged(false),
42     m_iBroadcastId(-1),
43     m_iGenreType(0),
44     m_iGenreSubType(0),
45     m_iParentalRating(0),
46     m_iStarRating(0),
47     m_iSeriesNumber(0),
48     m_iEpisodeNumber(0),
49     m_iEpisodePart(0),
50     m_iUniqueBroadcastID(-1),
51     m_epg(NULL)
52 {
53   CPVRChannelPtr emptyChannel;
54   m_pvrChannel = emptyChannel;
55
56   CPVRTimerInfoTagPtr emptyTimer;
57   m_timer = emptyTimer;
58 }
59
60 CEpgInfoTag::CEpgInfoTag(CEpg *epg, PVR::CPVRChannelPtr pvrChannel, const CStdString &strTableName /* = StringUtils::EmptyString */, const CStdString &strIconPath /* = StringUtils::EmptyString */) :
61     m_bNotify(false),
62     m_bChanged(false),
63     m_iBroadcastId(-1),
64     m_iGenreType(0),
65     m_iGenreSubType(0),
66     m_iParentalRating(0),
67     m_iStarRating(0),
68     m_iSeriesNumber(0),
69     m_iEpisodeNumber(0),
70     m_iEpisodePart(0),
71     m_iUniqueBroadcastID(-1),
72     m_strIconPath(strIconPath),
73     m_epg(epg),
74     m_pvrChannel(pvrChannel)
75 {
76   CPVRTimerInfoTagPtr emptyTimer;
77   m_timer = emptyTimer;
78 }
79
80 CEpgInfoTag::CEpgInfoTag(const EPG_TAG &data) :
81     m_bNotify(false),
82     m_bChanged(false),
83     m_iBroadcastId(-1),
84     m_iGenreType(0),
85     m_iGenreSubType(0),
86     m_iParentalRating(0),
87     m_iStarRating(0),
88     m_iSeriesNumber(0),
89     m_iEpisodeNumber(0),
90     m_iEpisodePart(0),
91     m_iUniqueBroadcastID(-1),
92     m_epg(NULL)
93 {
94   CPVRChannelPtr emptyChannel;
95   m_pvrChannel = emptyChannel;
96
97   CPVRTimerInfoTagPtr emptyTimer;
98   m_timer = emptyTimer;
99
100   Update(data);
101 }
102
103 CEpgInfoTag::CEpgInfoTag(const CEpgInfoTag &tag) :
104     m_bNotify(tag.m_bNotify),
105     m_bChanged(tag.m_bChanged),
106     m_iBroadcastId(tag.m_iBroadcastId),
107     m_iGenreType(tag.m_iGenreType),
108     m_iGenreSubType(tag.m_iGenreSubType),
109     m_iParentalRating(tag.m_iParentalRating),
110     m_iStarRating(tag.m_iStarRating),
111     m_iSeriesNumber(tag.m_iSeriesNumber),
112     m_iEpisodeNumber(tag.m_iEpisodeNumber),
113     m_iEpisodePart(tag.m_iEpisodePart),
114     m_iUniqueBroadcastID(tag.m_iUniqueBroadcastID),
115     m_strTitle(tag.m_strTitle),
116     m_strPlotOutline(tag.m_strPlotOutline),
117     m_strPlot(tag.m_strPlot),
118     m_genre(tag.m_genre),
119     m_strEpisodeName(tag.m_strEpisodeName),
120     m_strIconPath(tag.m_strIconPath),
121     m_strFileNameAndPath(tag.m_strFileNameAndPath),
122     m_startTime(tag.m_startTime),
123     m_endTime(tag.m_endTime),
124     m_firstAired(tag.m_firstAired),
125     m_timer(tag.m_timer),
126     m_epg(tag.m_epg),
127     m_pvrChannel(tag.m_pvrChannel)
128 {
129 }
130
131 CEpgInfoTag::~CEpgInfoTag()
132 {
133   ClearTimer();
134 }
135
136 bool CEpgInfoTag::operator ==(const CEpgInfoTag& right) const
137 {
138   if (this == &right) return true;
139
140   CSingleLock lock(m_critSection);
141   return (m_bNotify            == right.m_bNotify &&
142           m_bChanged           == right.m_bChanged &&
143           m_iBroadcastId       == right.m_iBroadcastId &&
144           m_iGenreType         == right.m_iGenreType &&
145           m_iGenreSubType      == right.m_iGenreSubType &&
146           m_iParentalRating    == right.m_iParentalRating &&
147           m_firstAired         == right.m_firstAired &&
148           m_iStarRating        == right.m_iStarRating &&
149           m_iSeriesNumber      == right.m_iSeriesNumber &&
150           m_iEpisodeNumber     == right.m_iEpisodeNumber &&
151           m_iEpisodePart       == right.m_iEpisodePart &&
152           m_iUniqueBroadcastID == right.m_iUniqueBroadcastID &&
153           m_strTitle           == right.m_strTitle &&
154           m_strPlotOutline     == right.m_strPlotOutline &&
155           m_strPlot            == right.m_strPlot &&
156           m_genre              == right.m_genre &&
157           m_strEpisodeName     == right.m_strEpisodeName &&
158           m_strIconPath        == right.m_strIconPath &&
159           m_strFileNameAndPath == right.m_strFileNameAndPath &&
160           m_startTime          == right.m_startTime &&
161           m_endTime            == right.m_endTime &&
162           m_pvrChannel         == right.m_pvrChannel);
163 }
164
165 bool CEpgInfoTag::operator !=(const CEpgInfoTag& right) const
166 {
167   if (this == &right) return false;
168
169   return !(*this == right);
170 }
171
172 CEpgInfoTag &CEpgInfoTag::operator =(const CEpgInfoTag &other)
173 {
174   CSingleLock lock(other.m_critSection);
175
176   m_bNotify            = other.m_bNotify;
177   m_bChanged           = other.m_bChanged;
178   m_iBroadcastId       = other.m_iBroadcastId;
179   m_iGenreType         = other.m_iGenreType;
180   m_iGenreSubType      = other.m_iGenreSubType;
181   m_iParentalRating    = other.m_iParentalRating;
182   m_iStarRating        = other.m_iStarRating;
183   m_iSeriesNumber      = other.m_iSeriesNumber;
184   m_iEpisodeNumber     = other.m_iEpisodeNumber;
185   m_iEpisodePart       = other.m_iEpisodePart;
186   m_iUniqueBroadcastID = other.m_iUniqueBroadcastID;
187   m_strTitle           = other.m_strTitle;
188   m_strPlotOutline     = other.m_strPlotOutline;
189   m_strPlot            = other.m_strPlot;
190   m_genre              = other.m_genre;
191   m_strEpisodeName     = other.m_strEpisodeName;
192   m_strIconPath        = other.m_strIconPath;
193   m_strFileNameAndPath = other.m_strFileNameAndPath;
194   m_startTime          = other.m_startTime;
195   m_endTime            = other.m_endTime;
196   m_firstAired         = other.m_firstAired;
197   m_timer              = other.m_timer;
198   m_epg                = other.m_epg;
199   m_pvrChannel         = other.m_pvrChannel;
200
201   return *this;
202 }
203
204 void CEpgInfoTag::Serialize(CVariant &value) const
205 {
206   value["broadcastid"] = m_iUniqueBroadcastID;
207   value["rating"] = m_iStarRating;
208   value["title"] = m_strTitle;
209   value["plotoutline"] = m_strPlotOutline;
210   value["plot"] = m_strPlot;
211   value["genre"] = m_genre;
212   value["filenameandpath"] = m_strFileNameAndPath;
213   value["starttime"] = m_startTime.IsValid() ? m_startTime.GetAsDBDateTime() : StringUtils::EmptyString;
214   value["endtime"] = m_endTime.IsValid() ? m_endTime.GetAsDBDateTime() : StringUtils::EmptyString;
215   value["runtime"] = StringUtils::Format("%d", GetDuration() / 60);
216   value["firstaired"] = m_firstAired.IsValid() ? m_firstAired.GetAsDBDate() : StringUtils::EmptyString;
217   value["progress"] = Progress();
218   value["progresspercentage"] = ProgressPercentage();
219   value["episodename"] = m_strEpisodeName;
220   value["episodenum"] = m_iEpisodeNumber;
221   value["episodepart"] = m_iEpisodePart;
222   value["hastimer"] = HasTimer();
223   value["isactive"] = IsActive();
224   value["wasactive"] = WasActive();
225 }
226
227 bool CEpgInfoTag::Changed(void) const
228 {
229   CSingleLock lock(m_critSection);
230   return m_bChanged;
231 }
232
233 bool CEpgInfoTag::IsActive(void) const
234 {
235   CDateTime now = CDateTime::GetUTCDateTime();
236   CSingleLock lock(m_critSection);
237   return (m_startTime <= now && m_endTime > now);
238 }
239
240 bool CEpgInfoTag::WasActive(void) const
241 {
242   CDateTime now = CDateTime::GetUTCDateTime();
243   CSingleLock lock(m_critSection);
244   return (m_endTime < now);
245 }
246
247 bool CEpgInfoTag::InTheFuture(void) const
248 {
249   CDateTime now = CDateTime::GetUTCDateTime();
250   CSingleLock lock(m_critSection);
251   return (m_startTime > now);
252 }
253
254 float CEpgInfoTag::ProgressPercentage(void) const
255 {
256   float fReturn(0);
257   int iDuration;
258   time_t currentTime, startTime, endTime;
259   CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(currentTime);
260
261   CSingleLock lock(m_critSection);
262   m_startTime.GetAsTime(startTime);
263   m_endTime.GetAsTime(endTime);
264   iDuration = endTime - startTime > 0 ? endTime - startTime : 3600;
265
266   if (currentTime >= startTime && currentTime <= endTime)
267     fReturn = ((float) currentTime - startTime) / iDuration * 100;
268   else if (currentTime > endTime)
269     fReturn = 100;
270
271   return fReturn;
272 }
273
274 int CEpgInfoTag::Progress(void) const
275 {
276   int iDuration;
277   time_t currentTime, startTime;
278   CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(currentTime);
279
280   CSingleLock lock(m_critSection);
281   m_startTime.GetAsTime(startTime);
282   iDuration = currentTime - startTime;
283   if (iDuration <= 0)
284     return 0;
285
286   return iDuration;
287 }
288
289 CEpgInfoTagPtr CEpgInfoTag::GetNextEvent(void) const
290 {
291   return GetTable()->GetNextEvent(*this);
292 }
293
294 CEpgInfoTagPtr CEpgInfoTag::GetPreviousEvent(void) const
295 {
296   return GetTable()->GetPreviousEvent(*this);
297 }
298
299 void CEpgInfoTag::SetUniqueBroadcastID(int iUniqueBroadcastID)
300 {
301   bool bUpdate(false);
302   {
303     CSingleLock lock(m_critSection);
304     if (m_iUniqueBroadcastID != iUniqueBroadcastID)
305     {
306       m_iUniqueBroadcastID = iUniqueBroadcastID;
307       m_bChanged = true;
308       bUpdate = true;
309     }
310   }
311   if (bUpdate)
312     UpdatePath();
313 }
314
315 int CEpgInfoTag::UniqueBroadcastID(void) const
316 {
317   CSingleLock lock(m_critSection);
318   return m_iUniqueBroadcastID;
319 }
320
321 void CEpgInfoTag::SetBroadcastId(int iId)
322 {
323   bool bUpdate(false);
324   {
325     CSingleLock lock(m_critSection);
326     if (m_iBroadcastId != iId)
327     {
328       m_iBroadcastId = iId;
329       m_bChanged = true;
330       bUpdate = true;
331     }
332   }
333   if (bUpdate)
334     UpdatePath();
335 }
336
337 int CEpgInfoTag::BroadcastId(void) const
338 {
339   CSingleLock lock(m_critSection);
340   return m_iBroadcastId;
341 }
342
343 CDateTime CEpgInfoTag::StartAsUTC(void) const
344 {
345   CSingleLock lock(m_critSection);
346   return m_startTime;
347 }
348
349 CDateTime CEpgInfoTag::StartAsLocalTime(void) const
350 {
351   CDateTime retVal;
352   CSingleLock lock(m_critSection);
353   retVal.SetFromUTCDateTime(m_startTime);
354   return retVal;
355 }
356
357 void CEpgInfoTag::SetStartFromUTC(const CDateTime &start)
358 {
359   bool bUpdate(false);
360   {
361     CSingleLock lock(m_critSection);
362     if (m_startTime != start)
363     {
364       m_startTime = start;
365       m_bChanged = true;
366       bUpdate = true;
367     }
368   }
369   if (bUpdate)
370     UpdatePath();
371 }
372
373 void CEpgInfoTag::SetStartFromLocalTime(const CDateTime &start)
374 {
375   CDateTime tmp = start.GetAsUTCDateTime();
376   SetStartFromUTC(tmp);
377 }
378
379 CDateTime CEpgInfoTag::EndAsUTC(void) const
380 {
381   CDateTime retVal;
382   CSingleLock lock(m_critSection);
383   retVal = m_endTime;
384   return retVal;
385 }
386
387 CDateTime CEpgInfoTag::EndAsLocalTime(void) const
388 {
389   CDateTime retVal;
390   CSingleLock lock(m_critSection);
391   retVal.SetFromUTCDateTime(m_endTime);
392   return retVal;
393 }
394
395 void CEpgInfoTag::SetEndFromUTC(const CDateTime &end)
396 {
397   bool bUpdate(false);
398   {
399     CSingleLock lock(m_critSection);
400     if (m_endTime != end)
401     {
402       m_endTime = end;
403       m_bChanged = true;
404       bUpdate = true;
405     }
406   }
407   if (bUpdate)
408     UpdatePath();
409 }
410
411 void CEpgInfoTag::SetEndFromLocalTime(const CDateTime &end)
412 {
413   CDateTime tmp = end.GetAsUTCDateTime();
414   SetEndFromUTC(tmp);
415 }
416
417 int CEpgInfoTag::GetDuration(void) const
418 {
419   time_t start, end;
420   CSingleLock lock(m_critSection);
421   m_startTime.GetAsTime(start);
422   m_endTime.GetAsTime(end);
423   return end - start > 0 ? end - start : 3600;
424 }
425
426 void CEpgInfoTag::SetTitle(const CStdString &strTitle)
427 {
428   bool bUpdate(false);
429   {
430     CSingleLock lock(m_critSection);
431     if (m_strTitle != strTitle)
432     {
433       m_strTitle = strTitle;
434       m_bChanged = true;
435       bUpdate = true;
436     }
437   }
438   if (bUpdate)
439     UpdatePath();
440 }
441
442 CStdString CEpgInfoTag::Title(bool bOverrideParental /* = false */) const
443 {
444   CStdString strTitle;
445   bool bParentalLocked(false);
446
447   {
448     CSingleLock lock(m_critSection);
449     strTitle = m_strTitle;
450     if (m_pvrChannel)
451       bParentalLocked = g_PVRManager.IsParentalLocked(*m_pvrChannel);
452   }
453
454   if (!bOverrideParental && bParentalLocked)
455     strTitle = g_localizeStrings.Get(19266); // parental locked
456   else if (strTitle.empty() && !CSettings::Get().GetBool("epg.hidenoinfoavailable"))
457     strTitle = g_localizeStrings.Get(19055); // no information available
458
459   return strTitle;
460 }
461
462 void CEpgInfoTag::SetPlotOutline(const CStdString &strPlotOutline)
463 {
464   bool bUpdate(false);
465   {
466     CSingleLock lock(m_critSection);
467     if (m_strPlotOutline != strPlotOutline)
468     {
469       m_strPlotOutline = strPlotOutline;
470       m_bChanged = true;
471       bUpdate = true;
472     }
473   }
474   if (bUpdate)
475     UpdatePath();
476 }
477
478 CStdString CEpgInfoTag::PlotOutline(bool bOverrideParental /* = false */) const
479 {
480   CStdString retVal;
481   CSingleLock lock(m_critSection);
482   if (bOverrideParental || !m_pvrChannel || !g_PVRManager.IsParentalLocked(*m_pvrChannel))
483     retVal = m_strPlotOutline;
484
485   return retVal;
486 }
487
488 void CEpgInfoTag::SetPlot(const CStdString &strPlot)
489 {
490   bool bUpdate(false);
491   {
492     CSingleLock lock(m_critSection);
493     bUpdate = !m_strPlot.Equals(strPlot);
494     m_bChanged |= bUpdate;
495     m_strPlot = strPlot;
496   }
497   if (bUpdate)
498     UpdatePath();
499 }
500
501 CStdString CEpgInfoTag::Plot(bool bOverrideParental /* = false */) const
502 {
503   CStdString retVal;
504   CSingleLock lock(m_critSection);
505   if (bOverrideParental || !m_pvrChannel || !g_PVRManager.IsParentalLocked(*m_pvrChannel))
506     retVal = m_strPlot;
507
508   return retVal;
509 }
510
511 void CEpgInfoTag::SetGenre(int iID, int iSubID, const char* strGenre)
512 {
513   bool bUpdate(false);
514   {
515     CSingleLock lock(m_critSection);
516     if (m_iGenreType != iID || m_iGenreSubType != iSubID)
517     {
518       m_iGenreType    = iID;
519       m_iGenreSubType = iSubID;
520       if ((iID == EPG_GENRE_USE_STRING) && (strGenre != NULL) && (strlen(strGenre) > 0))
521       {
522         /* Type and sub type are not given. No EPG color coding possible
523          * Use the provided genre description as backup. */
524         m_genre = StringUtils::Split(strGenre, g_advancedSettings.m_videoItemSeparator);
525       }
526       else
527       {
528         /* Determine the genre description from the type and subtype IDs */
529         m_genre = StringUtils::Split(CEpg::ConvertGenreIdToString(iID, iSubID), g_advancedSettings.m_videoItemSeparator);
530       }
531       m_bChanged = true;
532       bUpdate = true;
533     }
534   }
535   if (bUpdate)
536     UpdatePath();
537 }
538
539 int CEpgInfoTag::GenreType(void) const
540 {
541   CSingleLock lock(m_critSection);
542   return m_iGenreType;
543 }
544
545 int CEpgInfoTag::GenreSubType(void) const
546 {
547   CSingleLock lock(m_critSection);
548   return m_iGenreSubType;
549 }
550
551 const vector<string> CEpgInfoTag::Genre(void) const
552 {
553   vector<string> retVal;
554   CSingleLock lock(m_critSection);
555   retVal = m_genre;
556   return retVal;
557 }
558
559 CDateTime CEpgInfoTag::FirstAiredAsUTC(void) const
560 {
561   CDateTime retVal;
562   CSingleLock lock(m_critSection);
563   retVal = m_firstAired;
564   return retVal;
565 }
566
567 CDateTime CEpgInfoTag::FirstAiredAsLocalTime(void) const
568 {
569   CDateTime retVal;
570   CSingleLock lock(m_critSection);
571   retVal.SetFromUTCDateTime(m_firstAired);
572   return retVal;
573 }
574
575 void CEpgInfoTag::SetFirstAiredFromUTC(const CDateTime &firstAired)
576 {
577   bool bUpdate(false);
578   {
579     CSingleLock lock(m_critSection);
580     if (m_firstAired != firstAired)
581     {
582       m_firstAired = firstAired;
583       m_bChanged = true;
584       bUpdate = true;
585     }
586   }
587   if (bUpdate)
588     UpdatePath();
589 }
590
591 void CEpgInfoTag::SetFirstAiredFromLocalTime(const CDateTime &firstAired)
592 {
593   CDateTime tmp = firstAired.GetAsUTCDateTime();
594   SetFirstAiredFromUTC(tmp);
595 }
596
597 void CEpgInfoTag::SetParentalRating(int iParentalRating)
598 {
599   bool bUpdate(false);
600   {
601     CSingleLock lock(m_critSection);
602     if (m_iParentalRating != iParentalRating)
603     {
604       m_iParentalRating = iParentalRating;
605       m_bChanged = true;
606       bUpdate = true;
607     }
608   }
609   if (bUpdate)
610     UpdatePath();
611 }
612
613 int CEpgInfoTag::ParentalRating(void) const
614 {
615   CSingleLock lock(m_critSection);
616   return m_iParentalRating;
617 }
618
619 void CEpgInfoTag::SetStarRating(int iStarRating)
620 {
621   bool bUpdate(false);
622   {
623     CSingleLock lock(m_critSection);
624     if (m_iStarRating != iStarRating)
625     {
626       m_iStarRating = iStarRating;
627       m_bChanged = true;
628       bUpdate = true;
629     }
630   }
631   if (bUpdate)
632     UpdatePath();
633 }
634
635 int CEpgInfoTag::StarRating(void) const
636 {
637   CSingleLock lock(m_critSection);
638   return m_iStarRating;
639 }
640
641 void CEpgInfoTag::SetNotify(bool bNotify)
642 {
643   bool bUpdate(false);
644   {
645     CSingleLock lock(m_critSection);
646     if (m_bNotify != bNotify)
647     {
648       m_bNotify = bNotify;
649       m_bChanged = true;
650       bUpdate = true;
651     }
652   }
653   if (bUpdate)
654     UpdatePath();
655 }
656
657 bool CEpgInfoTag::Notify(void) const
658 {
659   CSingleLock lock(m_critSection);
660   return m_bNotify;
661 }
662
663 void CEpgInfoTag::SetSeriesNum(int iSeriesNum)
664 {
665   bool bUpdate(false);
666   {
667     CSingleLock lock(m_critSection);
668     if (m_iSeriesNumber != iSeriesNum)
669     {
670       m_iSeriesNumber = iSeriesNum;
671       m_bChanged = true;
672       bUpdate = true;
673     }
674   }
675   if (bUpdate)
676     UpdatePath();
677 }
678
679 int CEpgInfoTag::SeriesNum(void) const
680 {
681   CSingleLock lock(m_critSection);
682   return m_iSeriesNumber;
683 }
684
685 void CEpgInfoTag::SetEpisodeNum(int iEpisodeNum)
686 {
687   bool bUpdate(false);
688   {
689     CSingleLock lock(m_critSection);
690     if (m_iEpisodeNumber != iEpisodeNum)
691     {
692       m_iEpisodeNumber = iEpisodeNum;
693       m_bChanged = true;
694       bUpdate = true;
695     }
696   }
697   if (bUpdate)
698     UpdatePath();
699 }
700
701 int CEpgInfoTag::EpisodeNum(void) const
702 {
703   CSingleLock lock(m_critSection);
704   return m_iEpisodeNumber;
705 }
706
707 void CEpgInfoTag::SetEpisodePart(int iEpisodePart)
708 {
709   bool bUpdate(false);
710   {
711     CSingleLock lock(m_critSection);
712     if (m_iEpisodePart != iEpisodePart)
713     {
714       m_iEpisodePart = iEpisodePart;
715       m_bChanged = true;
716       bUpdate = true;
717     }
718   }
719   if (bUpdate)
720     UpdatePath();
721 }
722
723 int CEpgInfoTag::EpisodePart(void) const
724 {
725   CSingleLock lock(m_critSection);
726   return m_iEpisodePart;
727 }
728
729 void CEpgInfoTag::SetEpisodeName(const CStdString &strEpisodeName)
730 {
731   bool bUpdate(false);
732   {
733     CSingleLock lock(m_critSection);
734     if (m_strEpisodeName != strEpisodeName)
735     {
736       m_strEpisodeName = strEpisodeName;
737       m_bChanged = true;
738       bUpdate = true;
739     }
740   }
741   if (bUpdate)
742     UpdatePath();
743 }
744
745 CStdString CEpgInfoTag::EpisodeName(void) const
746 {
747   CStdString retVal;
748   CSingleLock lock(m_critSection);
749   retVal = m_strEpisodeName;
750   return retVal;
751 }
752
753 void CEpgInfoTag::SetIcon(const CStdString &strIconPath)
754 {
755   bool bUpdate(false);
756   {
757     CSingleLock lock(m_critSection);
758     if (m_strIconPath != strIconPath)
759     {
760       m_strIconPath = strIconPath;
761       m_bChanged = true;
762       bUpdate = true;
763     }
764   }
765   if (bUpdate)
766     UpdatePath();
767 }
768
769 CStdString CEpgInfoTag::Icon(void) const
770 {
771   CStdString retVal;
772
773   CSingleLock lock(m_critSection);
774   retVal = m_strIconPath;
775   return retVal;
776 }
777
778 void CEpgInfoTag::SetPath(const CStdString &strFileNameAndPath)
779 {
780   CSingleLock lock(m_critSection);
781   if (m_strFileNameAndPath != strFileNameAndPath)
782   {
783     m_strFileNameAndPath = strFileNameAndPath;
784     m_bChanged = true;
785   }
786 }
787
788 CStdString CEpgInfoTag::Path(void) const
789 {
790   string retVal;
791   CSingleLock lock(m_critSection);
792   retVal = m_strFileNameAndPath;
793   return retVal;
794 }
795
796 //void CEpgInfoTag::SetTimer(CPVRTimerInfoTagPtr newTimer)
797 //{
798 //  CPVRTimerInfoTagPtr oldTimer;
799 //  {
800 //    CSingleLock lock(m_critSection);
801 //    oldTimer = m_timer;
802 //    m_timer = newTimer;
803 //  }
804 //  if (oldTimer)
805 //    oldTimer->ClearEpgTag();
806 //}
807
808 bool CEpgInfoTag::HasTimer(void) const
809 {
810   CSingleLock lock(m_critSection);
811   return m_timer != NULL;
812 }
813
814 CPVRTimerInfoTagPtr CEpgInfoTag::Timer(void) const
815 {
816   CSingleLock lock(m_critSection);
817   return m_timer;
818 }
819
820 void CEpgInfoTag::SetPVRChannel(PVR::CPVRChannelPtr channel)
821 {
822   CSingleLock lock(m_critSection);
823   m_pvrChannel = channel;
824 }
825
826 bool CEpgInfoTag::HasPVRChannel(void) const
827 {
828   CSingleLock lock(m_critSection);
829   return m_pvrChannel != NULL;
830 }
831
832 int CEpgInfoTag::PVRChannelNumber(void) const
833 {
834   CSingleLock lock(m_critSection);
835   return m_pvrChannel ? m_pvrChannel->ChannelNumber() : -1;
836 }
837
838 CStdString CEpgInfoTag::PVRChannelName(void) const
839 {
840   CStdString strReturn;
841   CSingleLock lock(m_critSection);
842   if (m_pvrChannel)
843     strReturn = m_pvrChannel->ChannelName();
844   return strReturn;
845 }
846
847 const PVR::CPVRChannelPtr CEpgInfoTag::ChannelTag(void) const
848 {
849   CSingleLock lock(m_critSection);
850   return m_pvrChannel;
851 }
852
853 void CEpgInfoTag::Update(const EPG_TAG &tag)
854 {
855   CSingleLock lock(m_critSection);
856   SetStartFromUTC(tag.startTime + g_advancedSettings.m_iPVRTimeCorrection);
857   SetEndFromUTC(tag.endTime + g_advancedSettings.m_iPVRTimeCorrection);
858   SetTitle(tag.strTitle);
859   SetPlotOutline(tag.strPlotOutline);
860   SetPlot(tag.strPlot);
861   SetGenre(tag.iGenreType, tag.iGenreSubType, tag.strGenreDescription);
862   SetParentalRating(tag.iParentalRating);
863   SetUniqueBroadcastID(tag.iUniqueBroadcastId);
864   SetNotify(tag.bNotify);
865   SetFirstAiredFromUTC(tag.firstAired + g_advancedSettings.m_iPVRTimeCorrection);
866   SetEpisodeNum(tag.iEpisodeNumber);
867   SetEpisodePart(tag.iEpisodePartNumber);
868   SetEpisodeName(tag.strEpisodeName);
869   SetStarRating(tag.iStarRating);
870   SetIcon(tag.strIconPath);
871 }
872
873 bool CEpgInfoTag::Update(const CEpgInfoTag &tag, bool bUpdateBroadcastId /* = true */)
874 {
875   bool bChanged(false);
876   {
877     CSingleLock lock(m_critSection);
878     bChanged = (
879         m_strTitle           != tag.m_strTitle ||
880         m_strPlotOutline     != tag.m_strPlotOutline ||
881         m_strPlot            != tag.m_strPlot ||
882         m_startTime          != tag.m_startTime ||
883         m_endTime            != tag.m_endTime ||
884         m_iGenreType         != tag.m_iGenreType ||
885         m_iGenreSubType      != tag.m_iGenreSubType ||
886         m_firstAired         != tag.m_firstAired ||
887         m_iParentalRating    != tag.m_iParentalRating ||
888         m_iStarRating        != tag.m_iStarRating ||
889         m_bNotify            != tag.m_bNotify ||
890         m_iEpisodeNumber     != tag.m_iEpisodeNumber ||
891         m_iEpisodePart       != tag.m_iEpisodePart ||
892         m_iSeriesNumber      != tag.m_iSeriesNumber ||
893         m_strEpisodeName     != tag.m_strEpisodeName ||
894         m_iUniqueBroadcastID != tag.m_iUniqueBroadcastID ||
895         EpgID()              != tag.EpgID() ||
896         m_pvrChannel         != tag.m_pvrChannel ||
897         m_genre              != tag.m_genre
898     );
899     if (bUpdateBroadcastId)
900       bChanged = bChanged || m_iBroadcastId != tag.m_iBroadcastId;
901
902     if (bChanged)
903     {
904       if (bUpdateBroadcastId)
905         m_iBroadcastId       = tag.m_iBroadcastId;
906
907       m_strTitle           = tag.m_strTitle;
908       m_strPlotOutline     = tag.m_strPlotOutline;
909       m_strPlot            = tag.m_strPlot;
910       m_startTime          = tag.m_startTime;
911       m_endTime            = tag.m_endTime;
912       m_iGenreType         = tag.m_iGenreType;
913       m_iGenreSubType      = tag.m_iGenreSubType;
914       m_epg                = tag.m_epg;
915       m_pvrChannel         = tag.m_pvrChannel;
916       if (m_iGenreType == EPG_GENRE_USE_STRING)
917       {
918         /* No type/subtype. Use the provided description */
919         m_genre = tag.m_genre;
920       }
921       else
922       {
923         /* Determine genre description by type/subtype */
924         m_genre = StringUtils::Split(CEpg::ConvertGenreIdToString(tag.m_iGenreType, tag.m_iGenreSubType), g_advancedSettings.m_videoItemSeparator);
925       }
926       m_firstAired         = tag.m_firstAired;
927       m_iParentalRating    = tag.m_iParentalRating;
928       m_iStarRating        = tag.m_iStarRating;
929       m_bNotify            = tag.m_bNotify;
930       m_iEpisodeNumber     = tag.m_iEpisodeNumber;
931       m_iEpisodePart       = tag.m_iEpisodePart;
932       m_iSeriesNumber      = tag.m_iSeriesNumber;
933       m_strEpisodeName     = tag.m_strEpisodeName;
934       m_iUniqueBroadcastID = tag.m_iUniqueBroadcastID;
935
936       m_bChanged = true;
937     }
938   }
939   if (bChanged)
940     UpdatePath();
941
942   return bChanged;
943 }
944
945 bool CEpgInfoTag::Persist(bool bSingleUpdate /* = true */)
946 {
947   bool bReturn = false;
948   CSingleLock lock(m_critSection);
949   if (!m_bChanged)
950     return true;
951
952 #if EPG_DEBUGGING
953   CLog::Log(LOGDEBUG, "Epg - %s - Infotag '%s' %s, persisting...", __FUNCTION__, m_strTitle.c_str(), m_iBroadcastId > 0 ? "has changes" : "is new");
954 #endif
955
956   CEpgDatabase *database = g_EpgContainer.GetDatabase();
957   if (!database || (bSingleUpdate && !database->IsOpen()))
958   {
959     CLog::Log(LOGERROR, "%s - could not open the database", __FUNCTION__);
960     return bReturn;
961   }
962
963   int iId = database->Persist(*this, bSingleUpdate);
964   if (iId >= 0)
965   {
966     bReturn = true;
967
968     if (iId > 0)
969     {
970       m_iBroadcastId = iId;
971       m_bChanged = false;
972     }
973   }
974
975   return bReturn;
976 }
977
978 void CEpgInfoTag::UpdatePath(void)
979 {
980   CStdString path;
981   {
982     CSingleLock lock(m_critSection);
983     path = StringUtils::Format("pvr://guide/%04i/%s.epg", EpgID(), m_startTime.GetAsDBDateTime().c_str());
984   }
985
986   SetPath(path);
987 }
988
989 const CEpg *CEpgInfoTag::GetTable() const
990 {
991   return m_epg;
992 }
993
994 const int CEpgInfoTag::EpgID(void) const
995 {
996   return m_epg ? m_epg->EpgID() : -1;
997 }
998
999 void CEpgInfoTag::SetTimer(CPVRTimerInfoTagPtr timer)
1000 {
1001   CSingleLock lock(m_critSection);
1002   m_timer = timer;
1003 }
1004
1005 void CEpgInfoTag::ClearTimer(void)
1006 {
1007   CPVRTimerInfoTagPtr previousTag;
1008   {
1009     CSingleLock lock(m_critSection);
1010     previousTag = m_timer;
1011     CPVRTimerInfoTagPtr empty;
1012     m_timer = empty;
1013   }
1014
1015   if (previousTag)
1016     previousTag->ClearEpgTag();
1017 }