MythTV  master
livetvchain.cpp
Go to the documentation of this file.
1 #include "livetvchain.h"
2 #include "mythcontext.h"
3 #include "mythdb.h"
4 #include "mythlogging.h"
5 #include "programinfo.h"
6 #include "mythsocket.h"
7 #include "cardutil.h"
8 
9 #define LOC QString("LiveTVChain(%1): ").arg(m_id)
10 
11 static inline void clear(LiveTVChainEntry &entry)
12 {
13  entry.chanid = 0;
14 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
15  entry.starttime.setTime_t(0);
16 #else
17  entry.starttime.setSecsSinceEpoch(0);
18 #endif
19  entry.endtime = QDateTime();
20  entry.discontinuity = true;
21  entry.hostprefix = QString();
22  entry.inputtype = QString();
23  entry.channum = QString();
24  entry.inputname = QString();
25 }
26 
31 {
33  LOG(VB_GENERAL, LOG_DEBUG, LOC + "ctor");
34 }
35 
37 {
38  LOG(VB_GENERAL, LOG_DEBUG, LOC + "dtor");
39 }
40 
41 QString LiveTVChain::InitializeNewChain(const QString &seed)
42 {
43  QDateTime curdt = MythDate::current();
44  m_id = QString("live-%1-%2").arg(seed).arg(curdt.toString(Qt::ISODate));
45  return m_id;
46 }
47 
48 void LiveTVChain::SetHostPrefix(const QString &prefix)
49 {
51 }
52 
53 void LiveTVChain::SetInputType(const QString &type)
54 {
55  m_inputtype = type;
56 }
57 
58 void LiveTVChain::LoadFromExistingChain(const QString &id)
59 {
60  m_id = id;
61  ReloadAll();
62 }
63 
64 void LiveTVChain::AppendNewProgram(ProgramInfo *pginfo, const QString& channum,
65  const QString& inputname, bool discont)
66 {
67  QMutexLocker lock(&m_lock);
68 
69  LiveTVChainEntry newent;
70  newent.chanid = pginfo->GetChanID();
71  newent.starttime = pginfo->GetRecordingStartTime();
72  newent.endtime = pginfo->GetRecordingEndTime();
73  newent.discontinuity = discont;
74  newent.hostprefix = m_hostprefix;
75  newent.inputtype = m_inputtype;
76  newent.channum = channum;
77  newent.inputname = inputname;
78 
79  m_chain.append(newent);
80 
82  query.prepare("INSERT INTO tvchain (chanid, starttime, endtime, chainid,"
83  " chainpos, discontinuity, watching, hostprefix, cardtype, "
84  " channame, input) "
85  "VALUES(:CHANID, :START, :END, :CHAINID, :CHAINPOS, "
86  " :DISCONT, :WATCHING, :PREFIX, :INPUTTYPE, :CHANNAME, "
87  " :INPUT );");
88  query.bindValue(":CHANID", pginfo->GetChanID());
89  query.bindValue(":START", pginfo->GetRecordingStartTime());
90  query.bindValue(":END", pginfo->GetRecordingEndTime());
91  query.bindValueNoNull(":CHAINID", m_id);
92  query.bindValue(":CHAINPOS", m_maxpos);
93  query.bindValue(":DISCONT", discont);
94  query.bindValue(":WATCHING", 0);
95  query.bindValue(":PREFIX", m_hostprefix);
96  query.bindValue(":INPUTTYPE", m_inputtype);
97  query.bindValue(":CHANNAME", channum);
98  query.bindValue(":INPUT", inputname);
99 
100  if (!query.exec() || !query.isActive())
101  MythDB::DBError("Chain: AppendNewProgram", query);
102  else
103  LOG(VB_RECORD, LOG_INFO, QString("Chain: Appended@%3 '%1_%2'")
104  .arg(newent.chanid)
106  .arg(m_maxpos));
107 
108  m_maxpos++;
109  BroadcastUpdate();
110 }
111 
113 {
114  QMutexLocker lock(&m_lock);
115 
116  MSqlQuery query(MSqlQuery::InitCon());
117  query.prepare("UPDATE tvchain SET endtime = :END "
118  "WHERE chanid = :CHANID AND starttime = :START ;");
119  query.bindValue(":END", pginfo->GetRecordingEndTime());
120  query.bindValue(":CHANID", pginfo->GetChanID());
121  query.bindValue(":START", pginfo->GetRecordingStartTime());
122 
123  if (!query.exec() || !query.isActive())
124  MythDB::DBError("Chain: FinishedRecording", query);
125  else
126  LOG(VB_RECORD, LOG_INFO,
127  QString("Chain: Updated endtime for '%1_%2' to %3")
128  .arg(pginfo->GetChanID())
131 
132  QList<LiveTVChainEntry>::iterator it;
133  for (it = m_chain.begin(); it != m_chain.end(); ++it)
134  {
135  if ((*it).chanid == pginfo->GetChanID() &&
136  (*it).starttime == pginfo->GetRecordingStartTime())
137  {
138  (*it).endtime = pginfo->GetRecordingEndTime();
139  }
140  }
141  BroadcastUpdate();
142 }
143 
145 {
146  QMutexLocker lock(&m_lock);
147 
148  QList<LiveTVChainEntry>::iterator it, del;
149  for (it = m_chain.begin(); it != m_chain.end(); ++it)
150  {
151  if ((*it).chanid == pginfo->GetChanID() &&
152  (*it).starttime == pginfo->GetRecordingStartTime())
153  {
154  del = it;
155  ++it;
156 
157  MSqlQuery query(MSqlQuery::InitCon());
158  if (it != m_chain.end())
159  {
160  (*it).discontinuity = true;
161  query.prepare("UPDATE tvchain SET discontinuity = :DISCONT "
162  "WHERE chanid = :CHANID AND starttime = :START "
163  "AND chainid = :CHAINID ;");
164  query.bindValue(":CHANID", (*it).chanid);
165  query.bindValue(":START", (*it).starttime);
166  query.bindValue(":CHAINID", m_id);
167  query.bindValue(":DISCONT", true);
168  if (!query.exec())
169  MythDB::DBError("LiveTVChain::DeleteProgram -- "
170  "discontinuity", query);
171  }
172 
173  query.prepare("DELETE FROM tvchain WHERE chanid = :CHANID "
174  "AND starttime = :START AND chainid = :CHAINID ;");
175  query.bindValue(":CHANID", (*del).chanid);
176  query.bindValue(":START", (*del).starttime);
177  query.bindValue(":CHAINID", m_id);
178  if (!query.exec())
179  MythDB::DBError("LiveTVChain::DeleteProgram -- delete", query);
180 
181  m_chain.erase(del);
182 
183  BroadcastUpdate();
184  break;
185  }
186  }
187 }
188 
190 {
191  QString message = QString("LIVETV_CHAIN UPDATE %1").arg(m_id);
192  MythEvent me(message, entriesToStringList());
193  gCoreContext->dispatch(me);
194 }
195 
197 {
198  QMutexLocker lock(&m_lock);
199 
200  m_chain.clear();
201 
202  MSqlQuery query(MSqlQuery::InitCon());
203  query.prepare("DELETE FROM tvchain WHERE chainid = :CHAINID ;");
204  query.bindValue(":CHAINID", m_id);
205 
206  if (!query.exec())
207  MythDB::DBError("LiveTVChain::DestroyChain", query);
208 }
209 
210 void LiveTVChain::ReloadAll(const QStringList &data)
211 {
212  QMutexLocker lock(&m_lock);
213 
214  int prev_size = m_chain.size();
215  if (data.isEmpty() || !entriesFromStringList(data))
216  {
217  m_chain.clear();
218 
219  MSqlQuery query(MSqlQuery::InitCon());
220  query.prepare("SELECT chanid, starttime, endtime, discontinuity, "
221  "chainpos, hostprefix, cardtype, channame, input "
222  "FROM tvchain "
223  "WHERE chainid = :CHAINID ORDER BY chainpos;");
224  query.bindValue(":CHAINID", m_id);
225 
226  if (query.exec() && query.isActive() && query.size() > 0)
227  {
228  while (query.next())
229  {
230  LiveTVChainEntry entry;
231  entry.chanid = query.value(0).toUInt();
232  entry.starttime =
233  MythDate::as_utc(query.value(1).toDateTime());
234  entry.endtime =
235  MythDate::as_utc(query.value(2).toDateTime());
236  entry.discontinuity = query.value(3).toBool();
237  entry.hostprefix = query.value(5).toString();
238  entry.inputtype = query.value(6).toString();
239  entry.channum = query.value(7).toString();
240  entry.inputname = query.value(8).toString();
241 
242  m_maxpos = query.value(4).toInt() + 1;
243 
244  m_chain.append(entry);
245  }
246  }
247  }
248 
250  if (m_curpos < 0)
251  m_curpos = 0;
252 
253  if (m_switchid >= 0)
255 
256  if (prev_size > m_chain.size())
257  {
258  LOG(VB_PLAYBACK, LOG_INFO, LOC +
259  QString("ReloadAll(): Removed %1 recording(s)")
260  .arg(prev_size - m_chain.size()));
261  LOG(VB_PLAYBACK, LOG_INFO, LOC + toString());
262  }
263  else if (prev_size < m_chain.size())
264  {
265  LOG(VB_PLAYBACK, LOG_INFO, LOC +
266  QString("ReloadAll(): Added %1 recording(s)")
267  .arg(m_chain.size() - prev_size));
268  LOG(VB_PLAYBACK, LOG_INFO, LOC + toString());
269  }
270 }
271 
272 void LiveTVChain::GetEntryAt(int at, LiveTVChainEntry &entry) const
273 {
274  QMutexLocker lock(&m_lock);
275 
276  int size = m_chain.count();
277  int new_at = (size && (at < 0 || at >= size)) ? size - 1 : at;
278 
279  if (size && new_at >= 0 && new_at < size)
280  entry = m_chain[new_at];
281  else
282  {
283  LOG(VB_GENERAL, LOG_ERR, QString("GetEntryAt(%1) failed.").arg(at));
284  if (at == -1)
285  LOG(VB_GENERAL, LOG_ERR, "It appears that your backend may "
286  "be misconfigured. Check your backend logs to determine "
287  "whether your inputs, lineups, channels, or storage "
288  "configuration are reporting errors. This issue is commonly "
289  "caused by failing to complete all setup steps properly. You "
290  "may wish to review the documentation for mythtv-setup.");
291  clear(entry);
292  }
293 }
294 
296 {
297  ProgramInfo *pginfo = new ProgramInfo(entry.chanid, entry.starttime);
298 
299  if (pginfo->GetChanID())
300  {
301  pginfo->SetPathname(entry.hostprefix + pginfo->GetBasename());
302  return pginfo;
303  }
304 
305  LOG(VB_GENERAL, LOG_ERR,
306  QString("EntryToProgram(%1@%2) failed to get pginfo")
307  .arg(entry.chanid).arg(entry.starttime.toString(Qt::ISODate)));
308  delete pginfo;
309  return nullptr;
310 }
311 
320 {
321  LiveTVChainEntry entry;
322  GetEntryAt(at, entry);
323 
324  return EntryToProgram(entry);
325 }
326 
330 int LiveTVChain::ProgramIsAt(uint chanid, const QDateTime &starttime) const
331 {
332  QMutexLocker lock(&m_lock);
333 
334  int count = 0;
335  QList<LiveTVChainEntry>::const_iterator it;
336  for (it = m_chain.begin(); it != m_chain.end(); ++it, ++count)
337  {
338  if ((*it).chanid == chanid &&
339  (*it).starttime == starttime)
340  {
341  return count;
342  }
343  }
344 
345  return -1;
346 }
347 
351 int LiveTVChain::ProgramIsAt(const ProgramInfo &pginfo) const
352 {
353  return ProgramIsAt(pginfo.GetChanID(), pginfo.GetRecordingStartTime());
354 }
355 
360 {
361  return GetLengthAtPos(m_curpos);
362 }
363 
368 {
369  QMutexLocker lock(&m_lock);
370  LiveTVChainEntry entry, nextentry;
371 
372  entry = m_chain[pos];
373  if (pos == (m_chain.count() - 1))
374  {
375  // We're on live program, it hasn't ended. Use current time as end time
376  return entry.starttime.secsTo(MythDate::current());
377  }
378 
379  // use begin time from the following program, as it's certain to be right
380  // the end time is set as per the EPG, but should playback be interrupted
381  // such as a channel change, the end value wouldn't have reflected the actual
382  // duration of the program
383  nextentry = m_chain[pos+1];
384  return entry.starttime.secsTo(nextentry.starttime);
385 }
386 
387 int LiveTVChain::TotalSize(void) const
388 {
389  return m_chain.count();
390 }
391 
393 {
394  QMutexLocker lock(&m_lock);
395 
396  m_cur_chanid = pginfo.GetChanID();
398 
399  m_curpos = ProgramIsAt(pginfo);
400  if (m_curpos < 0)
401  m_curpos = 0;
402  m_switchid = -1;
403 }
404 
405 bool LiveTVChain::HasNext(void) const
406 {
407  return (m_chain.count() - 1 > m_curpos);
408 }
409 
411 {
412  QMutexLocker lock(&m_lock);
413 
414  m_switchid = -1;
415  m_jumppos = INT_MAX;
416 }
417 
428 ProgramInfo *LiveTVChain::GetSwitchProgram(bool &discont, bool &newtype,
429  int &newid)
430 {
431  ReloadAll();
432  QMutexLocker lock(&m_lock);
433 
434  int id = m_switchid;
436  discont, newtype);
437  if (pginfo)
438  {
439  newid = id;
440  }
441  ClearSwitch();
442 
443  return pginfo;
444 }
445 
446 ProgramInfo *LiveTVChain::DoGetNextProgram(bool up, int curpos, int &newid,
447  bool &discont, bool &newtype)
448 {
449  LiveTVChainEntry oldentry, entry;
450  ProgramInfo *pginfo = nullptr;
451 
452  GetEntryAt(curpos, oldentry);
453 
454  if (newid < 0 || curpos == newid)
455  {
456  // already on the program
457  entry = oldentry;
458  pginfo = EntryToProgram(entry);
459  newid = curpos;
460  }
461  else
462  {
463  // try to find recordings during first pass
464  // we'll skip dummy and empty recordings
465  while (!pginfo && newid < m_chain.count() && newid >= 0)
466  {
467  GetEntryAt(newid, entry);
468 
469  bool at_last_entry =
470  ((newid > curpos) &&
471  (newid == m_chain.count()-1)) ||
472  ((newid <= curpos) && (newid == 0));
473 
474  // Skip dummy recordings, if possible.
475  if (at_last_entry || (entry.inputtype != "DUMMY"))
476  pginfo = EntryToProgram(entry);
477 
478  // Skip empty recordings, if possible
479  if (pginfo && (0 == pginfo->GetFilesize()) &&
480  newid < m_chain.count()-1)
481  {
482  LOG(VB_GENERAL, LOG_WARNING,
483  QString("Skipping empty program %1")
484  .arg(pginfo->MakeUniqueKey()));
485  delete pginfo;
486  pginfo = nullptr;
487  }
488 
489  if (!pginfo)
490  {
491  newid += up ? 1 : -1;
492  }
493  }
494 
495  if (!pginfo)
496  {
497  // didn't find in first pass, now get back to the next good one
498  // as this is the one we will use
499  do
500  {
501  newid += up ? -1 : 1;
502 
503  GetEntryAt(newid, entry);
504 
505  bool at_last_entry =
506  ((newid > curpos) &&
507  (newid == m_chain.count()-1)) ||
508  ((newid <= curpos) && (newid == 0));
509 
510  // Skip dummy recordings, if possible.
511  if (at_last_entry || (entry.inputtype != "DUMMY"))
512  pginfo = EntryToProgram(entry);
513 
514  // Skip empty recordings, if possible
515  if (pginfo && (0 == pginfo->GetFilesize()) &&
516  newid < m_chain.count()-1)
517  {
518  LOG(VB_GENERAL, LOG_WARNING,
519  QString("Skipping empty program %1")
520  .arg(pginfo->MakeUniqueKey()));
521  delete pginfo;
522  pginfo = nullptr;
523  }
524  }
525  while (!pginfo && newid < m_chain.count() && newid >= 0);
526 
527  if (!pginfo)
528  {
529  // still not found so abort (will never happen once playback has started)
530  return nullptr;
531  }
532  }
533  }
534 
535  discont = true;
536  if (curpos == newid - 1)
537  discont = entry.discontinuity;
538 
539  newtype = (oldentry.inputtype != entry.inputtype);
540 
541  // Some inputs can change their streams dramatically on a channel change...
542  if (discont)
544 
545  LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
546  QString("DoGetNextProgram: %1 -> ").arg(newid) + pginfo->toString());
547 
548  return pginfo;
549 }
550 
556 {
557  QMutexLocker lock(&m_lock);
558 
559  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SwitchTo(%1)").arg(num));
560 
561  int size = m_chain.count();
562  if ((num < 0) || (num >= size))
563  num = size - 1;
564 
565  if (m_curpos != num)
566  {
567  m_switchid = num;
569  }
570  else
571  LOG(VB_GENERAL, LOG_ERR, LOC + "SwitchTo() not switching to current");
572 
573  if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_DEBUG))
574  {
576  GetEntryAt(num, e);
577  QString msg = QString("%1_%2")
578  .arg(e.chanid)
580  LOG(VB_PLAYBACK, LOG_DEBUG,
581  LOC + QString("Entry@%1: '%2')").arg(num).arg(msg));
582  }
583 }
584 
591 {
592 #if 0
593  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "SwitchToNext("<<(up?"up":"down")<<")");
594 #endif
595  if (up && HasNext())
596  SwitchTo(m_curpos + 1);
597  else if (!up && HasPrev())
598  SwitchTo(m_curpos - 1);
599 }
600 
601 void LiveTVChain::JumpTo(int num, int pos)
602 {
603  m_jumppos = pos;
604  SwitchTo(num);
605 }
606 
616 void LiveTVChain::JumpToNext(bool up, int pos)
617 {
618  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("JumpToNext: %1 -> %2").arg(up).arg(pos));
619  if (pos >= 0)
620  {
621  m_jumppos = pos;
622  SwitchToNext(up);
623  }
624  else
625  {
626  QMutexLocker lock(&m_lock);
627 
628  int current = m_curpos, switchto = m_curpos;
629  bool discont = false, newtype = false;
630 
631  while (current >= 0 && current < m_chain.size())
632  {
633  switchto = current + (up ? 1 : -1);
634 
635  ProgramInfo *pginfo = DoGetNextProgram(up, current, switchto,
636  discont, newtype);
637  delete pginfo;
638 
639  if (switchto == current)
640  {
641  // we've reached the end
642  pos = up ? GetLengthAtPos(switchto) : 0;
643  break;
644  }
645 
646  int duration = GetLengthAtPos(switchto);
647 
648  pos += duration;
649 
650  if (pos >= 0)
651  {
652  if (up)
653  {
654  pos = - (pos - duration);
655  }
656  break;
657  }
658 
659  current = switchto;
660  }
661  m_switchid = switchto;
662  m_jumppos = pos;
664  }
665 }
666 
671 {
672  int ret = m_jumppos;
673  m_jumppos = 0;
674  return ret;
675 }
676 
677 QString LiveTVChain::GetChannelName(int pos) const
678 {
679  LiveTVChainEntry entry;
680  GetEntryAt(pos, entry);
681 
682  return entry.channum;
683 }
684 
685 QString LiveTVChain::GetInputName(int pos) const
686 {
687  LiveTVChainEntry entry;
688  GetEntryAt(pos, entry);
689 
690  return entry.inputname;
691 }
692 
693 QString LiveTVChain::GetInputType(int pos) const
694 {
695  LiveTVChainEntry entry;
696  GetEntryAt(pos, entry);
697 
698  return entry.inputtype;
699 }
700 
702 {
703  QMutexLocker lock(&m_sockLock);
704 
705  if (!m_inUseSocks.contains(sock))
706  m_inUseSocks.append(sock);
707 }
708 
709 bool LiveTVChain::IsHostSocket(const MythSocket *sock) const
710 {
711  QMutexLocker lock(&m_sockLock);
712  return m_inUseSocks.contains(const_cast<MythSocket*>(sock));
713 }
714 
716 {
717  QMutexLocker lock(&m_sockLock);
718  return m_inUseSocks.count();
719 }
720 
722 {
723  QMutexLocker lock(&m_sockLock);
724  m_inUseSocks.removeAll(sock);
725 }
726 
727 static QString toString(const LiveTVChainEntry &v)
728 {
729  return QString("%1: %2 (%3 to %4)%5")
730  .arg(v.inputtype,6).arg(v.chanid,4)
731  .arg(v.starttime.time().toString())
732  .arg(v.endtime.time().toString())
733  .arg(v.discontinuity?" discontinuous":"");
734 }
735 
736 QString LiveTVChain::toString() const
737 {
738  QMutexLocker lock(&m_lock);
739  QString ret = QString("LiveTVChain has %1 entries\n").arg(m_chain.size());
740  for (uint i = 0; i < (uint)m_chain.size(); i++)
741  {
742  ret += (QString((i==(uint)m_curpos) ? "* " : " ") +
743  ::toString(m_chain[i]) + "\n");
744  }
745  return ret;
746 }
747 
749 {
750  QMutexLocker lock(&m_lock);
751  QStringList ret;
752  ret << QString::number(m_maxpos);
753  for (int i = 0; i < m_chain.size(); i++)
754  {
755  ret << QString::number(m_chain[i].chanid);
756  ret << m_chain[i].starttime.toString(Qt::ISODate);
757  ret << m_chain[i].endtime.toString(Qt::ISODate);
758  ret << QString::number(m_chain[i].discontinuity);
759  ret << m_chain[i].hostprefix;
760  ret << m_chain[i].inputtype;
761  ret << m_chain[i].channum;
762  ret << m_chain[i].inputname;
763  }
764  return ret;
765 }
766 
767 bool LiveTVChain::entriesFromStringList(const QStringList &items)
768 {
769  int numItems = items.size();
770  QList<LiveTVChainEntry> chain;
771  int itemIdx = 0;
772  int maxpos = 0;
773  bool ok = false;
774  if (itemIdx < numItems)
775  maxpos = items[itemIdx++].toInt(&ok);
776  while (ok && itemIdx < numItems)
777  {
778  LiveTVChainEntry entry;
779  if (ok && itemIdx < numItems)
780  entry.chanid = items[itemIdx++].toUInt(&ok);
781  if (ok && itemIdx < numItems)
782  {
783  entry.starttime =
784  QDateTime::fromString(items[itemIdx++], Qt::ISODate);
785  ok = entry.starttime.isValid();
786  }
787  if (ok && itemIdx < numItems)
788  {
789  entry.endtime =
790  QDateTime::fromString(items[itemIdx++], Qt::ISODate);
791  ok = entry.endtime.isValid();
792  }
793  if (ok && itemIdx < numItems)
794  entry.discontinuity = (items[itemIdx++].toInt(&ok) != 0);
795  if (ok && itemIdx < numItems)
796  entry.hostprefix = items[itemIdx++];
797  if (ok && itemIdx < numItems)
798  entry.inputtype = items[itemIdx++];
799  if (ok && itemIdx < numItems)
800  entry.channum = items[itemIdx++];
801  if (ok && itemIdx < numItems)
802  entry.inputname = items[itemIdx++];
803  if (ok)
804  chain.append(entry);
805  }
806  if (ok)
807  {
808  QMutexLocker lock(&m_lock);
809  m_maxpos = maxpos;
810  m_chain = chain;
811  }
812  else
813  {
814  LOG(VB_PLAYBACK, LOG_INFO,
815  QString("Failed to deserialize TVChain - ") + items.join("|"));
816  }
817  return ok;
818 }
int GetJumpPos(void)
Returns the jump position in seconds and clears it.
#define LOC
Definition: livetvchain.cpp:9
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
QString toString() const
void DelHostSocket(MythSocket *sock)
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
int TotalSize(void) const
virtual uint64_t GetFilesize(void) const
void SetPathname(const QString &) const
QDateTime endtime
Definition: livetvchain.h:23
void DestroyChain(void)
General purpose reference counter.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
void BroadcastUpdate()
ProgramInfo * GetProgramAt(int at) const
Returns program at the desired location.
void SetHostSocket(MythSocket *sock)
void SetInputType(const QString &type)
Definition: livetvchain.cpp:53
Default UTC, "yyyyMMddhhmmss".
Definition: mythdate.h:15
QString m_id
Definition: livetvchain.h:106
int size(void) const
Definition: mythdbcon.h:203
QString m_hostprefix
Definition: livetvchain.h:111
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
void JumpToNext(bool up, int pos)
JumpToNext(bool up, int pos) jump to the next (up == true) or previous (up == false) liveTV program I...
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
uint m_cur_chanid
Definition: livetvchain.h:115
bool HasNext(void) const
void SwitchTo(int num)
Sets the recording to switch to.
static ProgramInfo * EntryToProgram(const LiveTVChainEntry &entry)
int GetLengthAtCurPos(void)
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:23
static bool IsChannelChangeDiscontinuous(const QString &rawtype)
Definition: cardutil.h:138
void LoadFromExistingChain(const QString &id)
Definition: livetvchain.cpp:58
QDateTime starttime
Definition: livetvchain.h:22
QString inputtype
Definition: livetvchain.h:26
QVariant value(int i) const
Definition: mythdbcon.h:198
QString MakeUniqueKey(void) const
Creates a unique string that can be used to identify an existing recording.
Definition: programinfo.h:331
static QString toString(const LiveTVChainEntry &v)
Holds information on recordings and videos.
Definition: programinfo.h:66
QDateTime m_cur_startts
Definition: livetvchain.h:116
void ReloadAll(const QStringList &data=QStringList())
QString m_inputtype
Definition: livetvchain.h:112
This class is used as a container for messages.
Definition: mythevent.h:16
QString GetChannelName(int pos=-1) const
QMutex m_sockLock
Definition: livetvchain.h:123
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:24
QList< LiveTVChainEntry > m_chain
Definition: livetvchain.h:107
QString InitializeNewChain(const QString &seed)
Definition: livetvchain.cpp:41
QString GetBasename(void) const
Definition: programinfo.h:336
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
uint HostSocketCount(void) const
QString GetInputType(int pos=-1) const
bool isActive(void) const
Definition: mythdbcon.h:204
QString hostprefix
Definition: livetvchain.h:25
void AppendNewProgram(ProgramInfo *pginfo, const QString &channum, const QString &inputname, bool discont)
Definition: livetvchain.cpp:64
void GetEntryAt(int at, LiveTVChainEntry &entry) const
QList< MythSocket * > m_inUseSocks
Definition: livetvchain.h:124
LiveTVChainEntry m_switchentry
Definition: livetvchain.h:119
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
void SetProgram(const ProgramInfo &pginfo)
static void clear(LiveTVChainEntry &entry)
Definition: livetvchain.cpp:11
ProgramInfo * DoGetNextProgram(bool up, int curpos, int &newid, bool &discont, bool &newtype)
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
bool HasPrev(void) const
Definition: livetvchain.h:61
void dispatch(const MythEvent &event)
void SetHostPrefix(const QString &prefix)
Definition: livetvchain.cpp:48
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
void DeleteProgram(ProgramInfo *pginfo)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void ClearSwitch(void)
QString GetInputName(int pos=-1) const
QMutex m_lock
Definition: livetvchain.h:109
void FinishedRecording(ProgramInfo *pginfo)
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
Definition: mythdbcon.cpp:868
ProgramInfo * GetSwitchProgram(bool &discont, bool &newtype, int &newid)
Returns the recording we should switch to.
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:364
bool entriesFromStringList(const QStringList &items)
int ProgramIsAt(uint chanid, const QDateTime &starttime) const
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:396
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:404
QStringList entriesToStringList() const
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
bool IsHostSocket(const MythSocket *sock) const
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
void SwitchToNext(bool up)
Sets the recording to switch to.
int GetLengthAtPos(int pos)
void JumpTo(int num, int pos)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
Default UTC.
Definition: mythdate.h:14
QString inputname
Definition: livetvchain.h:28