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