Merge pull request #5039 from CEikermann/patch-1
[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["parentalrating"] = m_iParentalRating;
208   value["rating"] = m_iStarRating;
209   value["title"] = m_strTitle;
210   value["plotoutline"] = m_strPlotOutline;
211   value["plot"] = m_strPlot;
212   value["genre"] = m_genre;
213   value["filenameandpath"] = m_strFileNameAndPath;
214   value["starttime"] = m_startTime.IsValid() ? m_startTime.GetAsDBDateTime() : StringUtils::EmptyString;
215   value["endtime"] = m_endTime.IsValid() ? m_endTime.GetAsDBDateTime() : StringUtils::EmptyString;
216   value["runtime"] = StringUtils::Format("%d", GetDuration() / 60);
217   value["firstaired"] = m_firstAired.IsValid() ? m_firstAired.GetAsDBDate() : StringUtils::EmptyString;
218   value["progress"] = Progress();
219   value["progresspercentage"] = ProgressPercentage();
220   value["episodename"] = m_strEpisodeName;
221   value["episodenum"] = m_iEpisodeNumber;
222   value["episodepart"] = m_iEpisodePart;
223   value["hastimer"] = HasTimer();
224   value["isactive"] = IsActive();
225   value["wasactive"] = WasActive();
226 }
227
228 bool CEpgInfoTag::Changed(void) const
229 {
230   CSingleLock lock(m_critSection);
231   return m_bChanged;
232 }
233
234 bool CEpgInfoTag::IsActive(void) const
235 {
236   CDateTime now = CDateTime::GetUTCDateTime();
237   CSingleLock lock(m_critSection);
238   return (m_startTime <= now && m_endTime > now);
239 }
240
241 bool CEpgInfoTag::WasActive(void) const
242 {
243   CDateTime now = CDateTime::GetUTCDateTime();
244   CSingleLock lock(m_critSection);
245   return (m_endTime < now);
246 }
247
248 bool CEpgInfoTag::InTheFuture(void) const
249 {
250   CDateTime now = CDateTime::GetUTCDateTime();
251   CSingleLock lock(m_critSection);
252   return (m_startTime > now);
253 }
254
255 float CEpgInfoTag::ProgressPercentage(void) const
256 {
257   float fReturn(0);
258   int iDuration;
259   time_t currentTime, startTime, endTime;
260   CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(currentTime);
261
262   CSingleLock lock(m_critSection);
263   m_startTime.GetAsTime(startTime);
264   m_endTime.GetAsTime(endTime);
265   iDuration = endTime - startTime > 0 ? endTime - startTime : 3600;
266
267   if (currentTime >= startTime && currentTime <= endTime)
268     fReturn = ((float) currentTime - startTime) / iDuration * 100;
269   else if (currentTime > endTime)
270     fReturn = 100;
271
272   return fReturn;
273 }
274
275 int CEpgInfoTag::Progress(void) const
276 {
277   int iDuration;
278   time_t currentTime, startTime;
279   CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(currentTime);
280
281   CSingleLock lock(m_critSection);
282   m_startTime.GetAsTime(startTime);
283   iDuration = currentTime - startTime;
284   if (iDuration <= 0)
285     return 0;
286
287   return iDuration;
288 }
289
290 CEpgInfoTagPtr CEpgInfoTag::GetNextEvent(void) const
291 {
292   return GetTable()->GetNextEvent(*this);
293 }
294
295 CEpgInfoTagPtr CEpgInfoTag::GetPreviousEvent(void) const
296 {
297   return GetTable()->GetPreviousEvent(*this);
298 }
299
300 void CEpgInfoTag::SetUniqueBroadcastID(int iUniqueBroadcastID)
301 {
302   bool bUpdate(false);
303   {
304     CSingleLock lock(m_critSection);
305     if (m_iUniqueBroadcastID != iUniqueBroadcastID)
306     {
307       m_iUniqueBroadcastID = iUniqueBroadcastID;
308       m_bChanged = true;
309       bUpdate = true;
310     }
311   }
312   if (bUpdate)
313     UpdatePath();
314 }
315
316 int CEpgInfoTag::UniqueBroadcastID(void) const
317 {
318   CSingleLock lock(m_critSection);
319   return m_iUniqueBroadcastID;
320 }
321
322 void CEpgInfoTag::SetBroadcastId(int iId)
323 {
324   bool bUpdate(false);
325   {
326     CSingleLock lock(m_critSection);
327     if (m_iBroadcastId != iId)
328     {
329       m_iBroadcastId = iId;
330       m_bChanged = true;
331       bUpdate = true;
332     }
333   }
334   if (bUpdate)
335     UpdatePath();
336 }
337
338 int CEpgInfoTag::BroadcastId(void) const
339 {
340   CSingleLock lock(m_critSection);
341   return m_iBroadcastId;
342 }
343
344 CDateTime CEpgInfoTag::StartAsUTC(void) const
345 {
346   CSingleLock lock(m_critSection);
347   return m_startTime;
348 }
349
350 CDateTime CEpgInfoTag::StartAsLocalTime(void) const
351 {
352   CDateTime retVal;
353   CSingleLock lock(m_critSection);
354   retVal.SetFromUTCDateTime(m_startTime);
355   return retVal;
356 }
357
358 void CEpgInfoTag::SetStartFromUTC(const CDateTime &start)
359 {
360   bool bUpdate(false);
361   {
362     CSingleLock lock(m_critSection);
363     if (m_startTime != start)
364     {
365       m_startTime = start;
366       m_bChanged = true;
367       bUpdate = true;
368     }
369   }
370   if (bUpdate)
371     UpdatePath();
372 }
373
374 void CEpgInfoTag::SetStartFromLocalTime(const CDateTime &start)
375 {
376   CDateTime tmp = start.GetAsUTCDateTime();
377   SetStartFromUTC(tmp);
378 }
379
380 CDateTime CEpgInfoTag::EndAsUTC(void) const
381 {
382   CDateTime retVal;
383   CSingleLock lock(m_critSection);
384   retVal = m_endTime;
385   return retVal;
386 }
387
388 CDateTime CEpgInfoTag::EndAsLocalTime(void) const
389 {
390   CDateTime retVal;
391   CSingleLock lock(m_critSection);
392   retVal.SetFromUTCDateTime(m_endTime);
393   return retVal;
394 }
395
396 void CEpgInfoTag::SetEndFromUTC(const CDateTime &end)
397 {
398   bool bUpdate(false);
399   {
400     CSingleLock lock(m_critSection);
401     if (m_endTime != end)
402     {
403       m_endTime = end;
404       m_bChanged = true;
405       bUpdate = true;
406     }
407   }
408   if (bUpdate)
409     UpdatePath();
410 }
411
412 void CEpgInfoTag::SetEndFromLocalTime(const CDateTime &end)
413 {
414   CDateTime tmp = end.GetAsUTCDateTime();
415   SetEndFromUTC(tmp);
416 }
417
418 int CEpgInfoTag::GetDuration(void) const
419 {
420   time_t start, end;
421   CSingleLock lock(m_critSection);
422   m_startTime.GetAsTime(start);
423   m_endTime.GetAsTime(end);
424   return end - start > 0 ? end - start : 3600;
425 }
426
427 void CEpgInfoTag::SetTitle(const CStdString &strTitle)
428 {
429   bool bUpdate(false);
430   {
431     CSingleLock lock(m_critSection);
432     if (m_strTitle != strTitle)
433     {
434       m_strTitle = strTitle;
435       m_bChanged = true;
436       bUpdate = true;
437     }
438   }
439   if (bUpdate)
440     UpdatePath();
441 }
442
443 CStdString CEpgInfoTag::Title(bool bOverrideParental /* = false */) const
444 {
445   CStdString strTitle;
446   bool bParentalLocked(false);
447
448   {
449     CSingleLock lock(m_critSection);
450     strTitle = m_strTitle;
451     if (m_pvrChannel)
452       bParentalLocked = g_PVRManager.IsParentalLocked(*m_pvrChannel);
453   }
454
455   if (!bOverrideParental && bParentalLocked)
456     strTitle = g_localizeStrings.Get(19266); // parental locked
457   else if (strTitle.empty() && !CSettings::Get().GetBool("epg.hidenoinfoavailable"))
458     strTitle = g_localizeStrings.Get(19055); // no information available
459
460   return strTitle;
461 }
462
463 void CEpgInfoTag::SetPlotOutline(const CStdString &strPlotOutline)
464 {
465   bool bUpdate(false);
466   {
467     CSingleLock lock(m_critSection);
468     if (m_strPlotOutline != strPlotOutline)
469     {
470       m_strPlotOutline = strPlotOutline;
471       m_bChanged = true;
472       bUpdate = true;
473     }
474   }
475   if (bUpdate)
476     UpdatePath();
477 }
478
479 CStdString CEpgInfoTag::PlotOutline(bool bOverrideParental /* = false */) const
480 {
481   CStdString retVal;
482   CSingleLock lock(m_critSection);
483   if (bOverrideParental || !m_pvrChannel || !g_PVRManager.IsParentalLocked(*m_pvrChannel))
484     retVal = m_strPlotOutline;
485
486   return retVal;
487 }
488
489 void CEpgInfoTag::SetPlot(const CStdString &strPlot)
490 {
491   bool bUpdate(false);
492   {
493     CSingleLock lock(m_critSection);
494     bUpdate = !m_strPlot.Equals(strPlot);
495     m_bChanged |= bUpdate;
496     m_strPlot = strPlot;
497   }
498   if (bUpdate)
499     UpdatePath();
500 }
501
502 CStdString CEpgInfoTag::Plot(bool bOverrideParental /* = false */) const
503 {
504   CStdString retVal;
505   CSingleLock lock(m_critSection);
506   if (bOverrideParental || !m_pvrChannel || !g_PVRManager.IsParentalLocked(*m_pvrChannel))
507     retVal = m_strPlot;
508
509   return retVal;
510 }
511
512 void CEpgInfoTag::SetGenre(int iID, int iSubID, const char* strGenre)
513 {
514   bool bUpdate(false);
515   {
516     CSingleLock lock(m_critSection);
517     if (m_iGenreType != iID || m_iGenreSubType != iSubID)
518     {
519       m_iGenreType    = iID;
520       m_iGenreSubType = iSubID;
521       if ((iID == EPG_GENRE_USE_STRING) && (strGenre != NULL) && (strlen(strGenre) > 0))
522       {
523         /* Type and sub type are not given. No EPG color coding possible
524          * Use the provided genre description as backup. */
525         m_genre = StringUtils::Split(strGenre, g_advancedSettings.m_videoItemSeparator);
526       }
527       else
528       {
529         /* Determine the genre description from the type and subtype IDs */
530         m_genre = StringUtils::Split(CEpg::ConvertGenreIdToString(iID, iSubID), g_advancedSettings.m_videoItemSeparator);
531       }
532       m_bChanged = true;
533       bUpdate = true;
534     }
535   }
536   if (bUpdate)
537     UpdatePath();
538 }
539
540 int CEpgInfoTag::GenreType(void) const
541 {
542   CSingleLock lock(m_critSection);
543   return m_iGenreType;
544 }
545
546 int CEpgInfoTag::GenreSubType(void) const
547 {
548   CSingleLock lock(m_critSection);
549   return m_iGenreSubType;
550 }
551
552 const vector<string> CEpgInfoTag::Genre(void) const
553 {
554   vector<string> retVal;
555   CSingleLock lock(m_critSection);
556   retVal = m_genre;
557   return retVal;
558 }
559
560 CDateTime CEpgInfoTag::FirstAiredAsUTC(void) const
561 {
562   CDateTime retVal;
563   CSingleLock lock(m_critSection);
564   retVal = m_firstAired;
565   return retVal;
566 }
567
568 CDateTime CEpgInfoTag::FirstAiredAsLocalTime(void) const
569 {
570   CDateTime retVal;
571   CSingleLock lock(m_critSection);
572   retVal.SetFromUTCDateTime(m_firstAired);
573   return retVal;
574 }
575
576 void CEpgInfoTag::SetFirstAiredFromUTC(const CDateTime &firstAired)
577 {
578   bool bUpdate(false);
579   {
580     CSingleLock lock(m_critSection);
581     if (m_firstAired != firstAired)
582     {
583       m_firstAired = firstAired;
584       m_bChanged = true;
585       bUpdate = true;
586     }
587   }
588   if (bUpdate)
589     UpdatePath();
590 }
591
592 void CEpgInfoTag::SetFirstAiredFromLocalTime(const CDateTime &firstAired)
593 {
594   CDateTime tmp = firstAired.GetAsUTCDateTime();
595   SetFirstAiredFromUTC(tmp);
596 }
597
598 void CEpgInfoTag::SetParentalRating(int iParentalRating)
599 {
600   bool bUpdate(false);
601   {
602     CSingleLock lock(m_critSection);
603     if (m_iParentalRating != iParentalRating)
604     {
605       m_iParentalRating = iParentalRating;
606       m_bChanged = true;
607       bUpdate = true;
608     }
609   }
610   if (bUpdate)
611     UpdatePath();
612 }
613
614 int CEpgInfoTag::ParentalRating(void) const
615 {
616   CSingleLock lock(m_critSection);
617   return m_iParentalRating;
618 }
619
620 void CEpgInfoTag::SetStarRating(int iStarRating)
621 {
622   bool bUpdate(false);
623   {
624     CSingleLock lock(m_critSection);
625     if (m_iStarRating != iStarRating)
626     {
627       m_iStarRating = iStarRating;
628       m_bChanged = true;
629       bUpdate = true;
630     }
631   }
632   if (bUpdate)
633     UpdatePath();
634 }
635
636 int CEpgInfoTag::StarRating(void) const
637 {
638   CSingleLock lock(m_critSection);
639   return m_iStarRating;
640 }
641
642 void CEpgInfoTag::SetNotify(bool bNotify)
643 {
644   bool bUpdate(false);
645   {
646     CSingleLock lock(m_critSection);
647     if (m_bNotify != bNotify)
648     {
649       m_bNotify = bNotify;
650       m_bChanged = true;
651       bUpdate = true;
652     }
653   }
654   if (bUpdate)
655     UpdatePath();
656 }
657
658 bool CEpgInfoTag::Notify(void) const
659 {
660   CSingleLock lock(m_critSection);
661   return m_bNotify;
662 }
663
664 void CEpgInfoTag::SetSeriesNum(int iSeriesNum)
665 {
666   bool bUpdate(false);
667   {
668     CSingleLock lock(m_critSection);
669     if (m_iSeriesNumber != iSeriesNum)
670     {
671       m_iSeriesNumber = iSeriesNum;
672       m_bChanged = true;
673       bUpdate = true;
674     }
675   }
676   if (bUpdate)
677     UpdatePath();
678 }
679
680 int CEpgInfoTag::SeriesNum(void) const
681 {
682   CSingleLock lock(m_critSection);
683   return m_iSeriesNumber;
684 }
685
686 void CEpgInfoTag::SetEpisodeNum(int iEpisodeNum)
687 {
688   bool bUpdate(false);
689   {
690     CSingleLock lock(m_critSection);
691     if (m_iEpisodeNumber != iEpisodeNum)
692     {
693       m_iEpisodeNumber = iEpisodeNum;
694       m_bChanged = true;
695       bUpdate = true;
696     }
697   }
698   if (bUpdate)
699     UpdatePath();
700 }
701
702 int CEpgInfoTag::EpisodeNum(void) const
703 {
704   CSingleLock lock(m_critSection);
705   return m_iEpisodeNumber;
706 }
707
708 void CEpgInfoTag::SetEpisodePart(int iEpisodePart)
709 {
710   bool bUpdate(false);
711   {
712     CSingleLock lock(m_critSection);
713     if (m_iEpisodePart != iEpisodePart)
714     {
715       m_iEpisodePart = iEpisodePart;
716       m_bChanged = true;
717       bUpdate = true;
718     }
719   }
720   if (bUpdate)
721     UpdatePath();
722 }
723
724 int CEpgInfoTag::EpisodePart(void) const
725 {
726   CSingleLock lock(m_critSection);
727   return m_iEpisodePart;
728 }
729
730 void CEpgInfoTag::SetEpisodeName(const CStdString &strEpisodeName)
731 {
732   bool bUpdate(false);
733   {
734     CSingleLock lock(m_critSection);
735     if (m_strEpisodeName != strEpisodeName)
736     {
737       m_strEpisodeName = strEpisodeName;
738       m_bChanged = true;
739       bUpdate = true;
740     }
741   }
742   if (bUpdate)
743     UpdatePath();
744 }
745
746 CStdString CEpgInfoTag::EpisodeName(void) const
747 {
748   CStdString retVal;
749   CSingleLock lock(m_critSection);
750   retVal = m_strEpisodeName;
751   return retVal;
752 }
753
754 void CEpgInfoTag::SetIcon(const CStdString &strIconPath)
755 {
756   bool bUpdate(false);
757   {
758     CSingleLock lock(m_critSection);
759     if (m_strIconPath != strIconPath)
760     {
761       m_strIconPath = strIconPath;
762       m_bChanged = true;
763       bUpdate = true;
764     }
765   }
766   if (bUpdate)
767     UpdatePath();
768 }
769
770 CStdString CEpgInfoTag::Icon(void) const
771 {
772   CStdString retVal;
773
774   CSingleLock lock(m_critSection);
775   retVal = m_strIconPath;
776   return retVal;
777 }
778
779 void CEpgInfoTag::SetPath(const CStdString &strFileNameAndPath)
780 {
781   CSingleLock lock(m_critSection);
782   if (m_strFileNameAndPath != strFileNameAndPath)
783   {
784     m_strFileNameAndPath = strFileNameAndPath;
785     m_bChanged = true;
786   }
787 }
788
789 CStdString CEpgInfoTag::Path(void) const
790 {
791   string retVal;
792   CSingleLock lock(m_critSection);
793   retVal = m_strFileNameAndPath;
794   return retVal;
795 }
796
797 //void CEpgInfoTag::SetTimer(CPVRTimerInfoTagPtr newTimer)
798 //{
799 //  CPVRTimerInfoTagPtr oldTimer;
800 //  {
801 //    CSingleLock lock(m_critSection);
802 //    oldTimer = m_timer;
803 //    m_timer = newTimer;
804 //  }
805 //  if (oldTimer)
806 //    oldTimer->ClearEpgTag();
807 //}
808
809 bool CEpgInfoTag::HasTimer(void) const
810 {
811   CSingleLock lock(m_critSection);
812   return m_timer != NULL;
813 }
814
815 CPVRTimerInfoTagPtr CEpgInfoTag::Timer(void) const
816 {
817   CSingleLock lock(m_critSection);
818   return m_timer;
819 }
820
821 void CEpgInfoTag::SetPVRChannel(PVR::CPVRChannelPtr channel)
822 {
823   CSingleLock lock(m_critSection);
824   m_pvrChannel = channel;
825 }
826
827 bool CEpgInfoTag::HasPVRChannel(void) const
828 {
829   CSingleLock lock(m_critSection);
830   return m_pvrChannel != NULL;
831 }
832
833 int CEpgInfoTag::PVRChannelNumber(void) const
834 {
835   CSingleLock lock(m_critSection);
836   return m_pvrChannel ? m_pvrChannel->ChannelNumber() : -1;
837 }
838
839 CStdString CEpgInfoTag::PVRChannelName(void) const
840 {
841   CStdString strReturn;
842   CSingleLock lock(m_critSection);
843   if (m_pvrChannel)
844     strReturn = m_pvrChannel->ChannelName();
845   return strReturn;
846 }
847
848 const PVR::CPVRChannelPtr CEpgInfoTag::ChannelTag(void) const
849 {
850   CSingleLock lock(m_critSection);
851   return m_pvrChannel;
852 }
853
854 void CEpgInfoTag::Update(const EPG_TAG &tag)
855 {
856   CSingleLock lock(m_critSection);
857   SetStartFromUTC(tag.startTime + g_advancedSettings.m_iPVRTimeCorrection);
858   SetEndFromUTC(tag.endTime + g_advancedSettings.m_iPVRTimeCorrection);
859   SetTitle(tag.strTitle);
860   SetPlotOutline(tag.strPlotOutline);
861   SetPlot(tag.strPlot);
862   SetGenre(tag.iGenreType, tag.iGenreSubType, tag.strGenreDescription);
863   SetParentalRating(tag.iParentalRating);
864   SetUniqueBroadcastID(tag.iUniqueBroadcastId);
865   SetNotify(tag.bNotify);
866   SetFirstAiredFromUTC(tag.firstAired + g_advancedSettings.m_iPVRTimeCorrection);
867   SetEpisodeNum(tag.iEpisodeNumber);
868   SetEpisodePart(tag.iEpisodePartNumber);
869   SetEpisodeName(tag.strEpisodeName);
870   SetStarRating(tag.iStarRating);
871   SetIcon(tag.strIconPath);
872 }
873
874 bool CEpgInfoTag::Update(const CEpgInfoTag &tag, bool bUpdateBroadcastId /* = true */)
875 {
876   bool bChanged(false);
877   {
878     CSingleLock lock(m_critSection);
879     bChanged = (
880         m_strTitle           != tag.m_strTitle ||
881         m_strPlotOutline     != tag.m_strPlotOutline ||
882         m_strPlot            != tag.m_strPlot ||
883         m_startTime          != tag.m_startTime ||
884         m_endTime            != tag.m_endTime ||
885         m_iGenreType         != tag.m_iGenreType ||
886         m_iGenreSubType      != tag.m_iGenreSubType ||
887         m_firstAired         != tag.m_firstAired ||
888         m_iParentalRating    != tag.m_iParentalRating ||
889         m_iStarRating        != tag.m_iStarRating ||
890         m_bNotify            != tag.m_bNotify ||
891         m_iEpisodeNumber     != tag.m_iEpisodeNumber ||
892         m_iEpisodePart       != tag.m_iEpisodePart ||
893         m_iSeriesNumber      != tag.m_iSeriesNumber ||
894         m_strEpisodeName     != tag.m_strEpisodeName ||
895         m_iUniqueBroadcastID != tag.m_iUniqueBroadcastID ||
896         EpgID()              != tag.EpgID() ||
897         m_pvrChannel         != tag.m_pvrChannel ||
898         m_genre              != tag.m_genre
899     );
900     if (bUpdateBroadcastId)
901       bChanged = bChanged || m_iBroadcastId != tag.m_iBroadcastId;
902
903     if (bChanged)
904     {
905       if (bUpdateBroadcastId)
906         m_iBroadcastId       = tag.m_iBroadcastId;
907
908       m_strTitle           = tag.m_strTitle;
909       m_strPlotOutline     = tag.m_strPlotOutline;
910       m_strPlot            = tag.m_strPlot;
911       m_startTime          = tag.m_startTime;
912       m_endTime            = tag.m_endTime;
913       m_iGenreType         = tag.m_iGenreType;
914       m_iGenreSubType      = tag.m_iGenreSubType;
915       m_epg                = tag.m_epg;
916       m_pvrChannel         = tag.m_pvrChannel;
917       if (m_iGenreType == EPG_GENRE_USE_STRING)
918       {
919         /* No type/subtype. Use the provided description */
920         m_genre = tag.m_genre;
921       }
922       else
923       {
924         /* Determine genre description by type/subtype */
925         m_genre = StringUtils::Split(CEpg::ConvertGenreIdToString(tag.m_iGenreType, tag.m_iGenreSubType), g_advancedSettings.m_videoItemSeparator);
926       }
927       m_firstAired         = tag.m_firstAired;
928       m_iParentalRating    = tag.m_iParentalRating;
929       m_iStarRating        = tag.m_iStarRating;
930       m_bNotify            = tag.m_bNotify;
931       m_iEpisodeNumber     = tag.m_iEpisodeNumber;
932       m_iEpisodePart       = tag.m_iEpisodePart;
933       m_iSeriesNumber      = tag.m_iSeriesNumber;
934       m_strEpisodeName     = tag.m_strEpisodeName;
935       m_iUniqueBroadcastID = tag.m_iUniqueBroadcastID;
936
937       m_bChanged = true;
938     }
939   }
940   if (bChanged)
941     UpdatePath();
942
943   return bChanged;
944 }
945
946 bool CEpgInfoTag::Persist(bool bSingleUpdate /* = true */)
947 {
948   bool bReturn = false;
949   CSingleLock lock(m_critSection);
950   if (!m_bChanged)
951     return true;
952
953 #if EPG_DEBUGGING
954   CLog::Log(LOGDEBUG, "Epg - %s - Infotag '%s' %s, persisting...", __FUNCTION__, m_strTitle.c_str(), m_iBroadcastId > 0 ? "has changes" : "is new");
955 #endif
956
957   CEpgDatabase *database = g_EpgContainer.GetDatabase();
958   if (!database || (bSingleUpdate && !database->IsOpen()))
959   {
960     CLog::Log(LOGERROR, "%s - could not open the database", __FUNCTION__);
961     return bReturn;
962   }
963
964   int iId = database->Persist(*this, bSingleUpdate);
965   if (iId >= 0)
966   {
967     bReturn = true;
968
969     if (iId > 0)
970     {
971       m_iBroadcastId = iId;
972       m_bChanged = false;
973     }
974   }
975
976   return bReturn;
977 }
978
979 void CEpgInfoTag::UpdatePath(void)
980 {
981   CStdString path;
982   {
983     CSingleLock lock(m_critSection);
984     path = StringUtils::Format("pvr://guide/%04i/%s.epg", EpgID(), m_startTime.GetAsDBDateTime().c_str());
985   }
986
987   SetPath(path);
988 }
989
990 const CEpg *CEpgInfoTag::GetTable() const
991 {
992   return m_epg;
993 }
994
995 const int CEpgInfoTag::EpgID(void) const
996 {
997   return m_epg ? m_epg->EpgID() : -1;
998 }
999
1000 void CEpgInfoTag::SetTimer(CPVRTimerInfoTagPtr timer)
1001 {
1002   CSingleLock lock(m_critSection);
1003   m_timer = timer;
1004 }
1005
1006 void CEpgInfoTag::ClearTimer(void)
1007 {
1008   CPVRTimerInfoTagPtr previousTag;
1009   {
1010     CSingleLock lock(m_critSection);
1011     previousTag = m_timer;
1012     CPVRTimerInfoTagPtr empty;
1013     m_timer = empty;
1014   }
1015
1016   if (previousTag)
1017     previousTag->ClearEpgTag();
1018 }