MythTV master
filldata.cpp
Go to the documentation of this file.
1// POSIX headers
2#include <unistd.h>
3
4// C++ headers
5#include <algorithm>
6#include <cstdlib>
7#include <fstream>
8
9// Qt headers
10#include <QDateTime>
11#include <QDir>
12#include <QFile>
13#include <QList>
14#include <QMap>
15#include <QTextStream>
16
17// MythTV headers
18#include "libmythbase/compat.h"
22#include "libmythbase/mythdb.h"
28#include "libmythtv/videosource.h" // for is_grabber..
29
30// filldata headers
31#include "filldata.h"
32
33#define LOC QString("FillData: ")
34#define LOC_WARN QString("FillData, Warning: ")
35#define LOC_ERR QString("FillData, Error: ")
36
38{
39 QDateTime qdtNow = MythDate::current();
40 return gCoreContext->SaveSettingOnHost("mythfilldatabaseLastRunEnd",
41 qdtNow.toString(Qt::ISODate),
42 nullptr);
43}
44
46{
48 QDateTime qdtNow = MythDate::current();
49 return gCoreContext->SaveSettingOnHost("mythfilldatabaseLastRunStart",
50 qdtNow.toString(Qt::ISODate),
51 nullptr);
52}
53
54bool updateLastRunStatus(QString &status)
55{
56 return gCoreContext->SaveSettingOnHost("mythfilldatabaseLastRunStatus",
57 status,
58 nullptr);
59}
60
62{
63 QDateTime nextSuggestedTime = MythDate::current().addDays(1);
64 return gCoreContext->SaveSettingOnHost("MythFillSuggestedRunTime",
65 nextSuggestedTime.toString(Qt::ISODate),
66 nullptr);
67}
68
69void FillData::SetRefresh(int day, bool set)
70{
71 if (kRefreshClear == day)
72 {
73 m_refreshAll = set;
74 m_refreshDay.clear();
75 }
76 else if (kRefreshAll == day)
77 {
78 m_refreshAll = set;
79 }
80 else
81 {
82 m_refreshDay[(uint)day] = set;
83 }
84}
85
86// XMLTV stuff
87bool FillData::GrabDataFromFile(int id, const QString &filename)
88{
89 ChannelInfoList chanlist;
90 QMap<QString, QList<ProgInfo> > proglist;
91
92 if (!m_xmltvParser.parseFile(filename, &chanlist, &proglist))
93 return false;
94
95 m_chanData.handleChannels(id, &chanlist);
97 {
98 if (proglist.count() != 0)
99 {
100 LOG(VB_GENERAL, LOG_INFO, "Skipping program guide updates");
101 }
102 }
103 else
104 {
105 if (proglist.count() == 0)
106 {
107 LOG(VB_GENERAL, LOG_INFO, "No programs found in data.");
108 m_endOfData = true;
109 }
110 else
111 {
112 ProgramData::HandlePrograms(id, proglist);
113 }
114 }
115 return true;
116}
117
118bool FillData::GrabData(const DataSource& source, int offset)
119{
120 QString xmltv_grabber = source.xmltvgrabber;
121
122 const QString templatename = "/tmp/mythXXXXXX";
123 const QString tempfilename = createTempFile(templatename);
124 if (templatename == tempfilename)
125 {
126 m_fatalErrors.push_back("Failed to create temporary file.");
127 return false;
128 }
129
130 QString filename = QString(tempfilename);
131
132 QString configfile;
133
135 query1.prepare("SELECT configpath FROM videosource"
136 " WHERE sourceid = :ID AND configpath IS NOT NULL");
137 query1.bindValue(":ID", source.id);
138 if (!query1.exec())
139 {
140 MythDB::DBError("FillData::grabData", query1);
141 return false;
142 }
143
144 if (query1.next())
145 configfile = query1.value(0).toString();
146 else
147 configfile = QString("%1/%2.xmltv").arg(GetConfDir(), source.name);
148
149 LOG(VB_GENERAL, LOG_INFO,
150 QString("XMLTV config file is: %1").arg(configfile));
151
152 QString command = QString("nice %1 --config-file '%2' --output %3")
153 .arg(xmltv_grabber, configfile, filename);
154
156 {
157 command += " --list-channels";
158 }
159 else if (source.xmltvgrabber_prefmethod != "allatonce" || m_noAllAtOnce || m_onlyUpdateChannels)
160 {
161 // XMLTV Docs don't recommend grabbing one day at a
162 // time but the current MythTV code is heavily geared
163 // that way so until it is re-written behave as
164 // we always have done.
165 command += QString(" --days 1 --offset %1").arg(offset);
166 }
167
168 if (!VERBOSE_LEVEL_CHECK(VB_XMLTV, LOG_ANY))
169 command += " --quiet";
170
171 // Append additional arguments passed to mythfilldatabase
172 // using --graboptions
173 if (!m_grabOptions.isEmpty())
174 {
175 command += m_grabOptions;
176 LOG(VB_XMLTV, LOG_INFO,
177 QString("Using graboptions: %1").arg(m_grabOptions));
178 }
179
180 QString status = QObject::tr("currently running.");
181
183 updateLastRunStatus(status);
184
185 LOG(VB_XMLTV, LOG_INFO, QString("Grabber Command: %1").arg(command));
186
187 LOG(VB_XMLTV, LOG_INFO,
188 "----------------- Start of XMLTV output -----------------");
189
190 MythSystemLegacy run_grabber(command, kMSRunShell | kMSStdErr);
191
192 run_grabber.Run();
193 uint systemcall_status = run_grabber.Wait();
194 bool succeeded = (systemcall_status == GENERIC_EXIT_OK);
195
196 QByteArray result = run_grabber.ReadAllErr();
197 QTextStream ostream(result);
198 while (!ostream.atEnd())
199 {
200 QString line = ostream.readLine().simplified();
201 LOG(VB_XMLTV, LOG_INFO, line);
202 }
203
204 LOG(VB_XMLTV, LOG_INFO,
205 "------------------ End of XMLTV output ------------------");
206
208
209 status = QObject::tr("Successful.");
210
211 if (!succeeded)
212 {
213 if (systemcall_status == GENERIC_EXIT_KILLED)
214 {
215 m_interrupted = true;
216 status = QObject::tr("FAILED: XMLTV grabber ran but was interrupted.");
217 LOG(VB_GENERAL, LOG_ERR,
218 QString("XMLTV grabber ran but was interrupted."));
219 }
220 else
221 {
222 status = QObject::tr("FAILED: XMLTV grabber returned error code %1.")
223 .arg(systemcall_status);
224 LOG(VB_GENERAL, LOG_ERR,
225 QString("XMLTV grabber returned error code %1")
226 .arg(systemcall_status));
227 }
228 }
229
230 updateLastRunStatus(status);
231
232 succeeded &= GrabDataFromFile(source.id, filename);
233
234 QFile thefile(filename);
235 thefile.remove();
236
237 return succeeded;
238}
239
246{
247 DataSourceList::iterator it;
248
249 QString status;
250 QString querystr;
252 QDateTime GuideDataBefore;
253 QDateTime GuideDataAfter;
254 int failures = 0;
255 int externally_handled = 0;
256 int total_sources = sourcelist.size();
257 int source_channels = 0;
258
259 QString sidStr = QString("Updating source #%1 (%2) with grabber %3");
260
261 m_needPostGrabProc = false;
262 int nonewdata = 0;
263
264 for (it = sourcelist.begin(); it != sourcelist.end(); ++it)
265 {
266 if (!m_fatalErrors.empty())
267 break;
268
269 QString xmltv_grabber = (*it).xmltvgrabber;
270
271 if (xmltv_grabber == "datadirect" ||
272 xmltv_grabber == "schedulesdirect1")
273 {
274 LOG(VB_GENERAL, LOG_ERR,
275 QString("Source %1 is configured to use the DataDirect guide"
276 "service from Schedules Direct. That service is no "
277 "longer supported by MythTV. Update to use one of "
278 "the XMLTV grabbers that use the JSON-based guide "
279 "service from Schedules Direct.")
280 .arg((*it).id));
281 continue;
282 }
283
284 query.prepare("SELECT MAX(endtime) "
285 "FROM program p "
286 "LEFT JOIN channel c ON p.chanid=c.chanid "
287 "WHERE c.deleted IS NULL AND c.sourceid= :SRCID "
288 " AND manualid = 0 AND c.xmltvid != '';");
289 query.bindValue(":SRCID", (*it).id);
290
291 if (query.exec() && query.next())
292 {
293 if (!query.isNull(0))
294 GuideDataBefore =
295 MythDate::fromString(query.value(0).toString());
296 }
297
298 m_channelUpdateRun = false;
299 m_endOfData = false;
300
301 if (xmltv_grabber == "eitonly")
302 {
303 LOG(VB_GENERAL, LOG_INFO,
304 QString("Source %1 configured to use only the "
305 "broadcasted guide data. Skipping.") .arg((*it).id));
306
307 externally_handled++;
310 continue;
311 }
312 if (xmltv_grabber.trimmed().isEmpty() ||
313 xmltv_grabber == "/bin/true" ||
314 xmltv_grabber == "none")
315 {
316 LOG(VB_GENERAL, LOG_INFO,
317 QString("Source %1 configured with no grabber. Nothing to do.")
318 .arg((*it).id));
319
320 externally_handled++;
323 continue;
324 }
325
326 LOG(VB_GENERAL, LOG_INFO, sidStr.arg(QString::number((*it).id),
327 (*it).name,
328 xmltv_grabber));
329
330 query.prepare(
331 "SELECT COUNT(chanid) FROM channel "
332 "WHERE deleted IS NULL AND "
333 " sourceid = :SRCID AND xmltvid != ''");
334 query.bindValue(":SRCID", (*it).id);
335
336 if (query.exec() && query.next())
337 {
338 source_channels = query.value(0).toInt();
339 if (source_channels > 0)
340 {
341 LOG(VB_GENERAL, LOG_INFO,
342 QString("Found %1 channels for source %2 which use grabber")
343 .arg(source_channels).arg((*it).id));
344 }
345 else
346 {
347 LOG(VB_GENERAL, LOG_INFO,
348 QString("No channels are configured to use grabber (none have XMLTVIDs)."));
349 }
350 }
351 else
352 {
353 source_channels = 0;
354 LOG(VB_GENERAL, LOG_INFO,
355 QString("Can't get a channel count for source id %1")
356 .arg((*it).id));
357 }
358
359 bool hasprefmethod = false;
360
361 if (is_grabber_external(xmltv_grabber))
362 {
363 uint flags = kMSRunShell | kMSStdOut;
364 MythSystemLegacy grabber_capabilities_proc(xmltv_grabber,
365 QStringList("--capabilities"),
366 flags);
367 grabber_capabilities_proc.Run(25s);
368 if (grabber_capabilities_proc.Wait() != GENERIC_EXIT_OK)
369 {
370 LOG(VB_GENERAL, LOG_ERR,
371 QString("%1 --capabilities failed or we timed out waiting."
372 " You may need to upgrade your xmltv grabber")
373 .arg(xmltv_grabber));
374 }
375 else
376 {
377 QByteArray result = grabber_capabilities_proc.ReadAll();
378 QTextStream ostream(result);
379 QString capabilities;
380 while (!ostream.atEnd())
381 {
382 QString capability
383 = ostream.readLine().simplified();
384
385 if (capability.isEmpty())
386 continue;
387
388 capabilities += capability + ' ';
389
390 if (capability == "baseline")
391 (*it).xmltvgrabber_baseline = true;
392
393 if (capability == "manualconfig")
394 (*it).xmltvgrabber_manualconfig = true;
395
396 if (capability == "cache")
397 (*it).xmltvgrabber_cache = true;
398
399 if (capability == "apiconfig")
400 (*it).xmltvgrabber_apiconfig = true;
401
402 if (capability == "lineups")
403 (*it).xmltvgrabber_lineups = true;
404
405 if (capability == "preferredmethod")
406 hasprefmethod = true;
407 }
408 LOG(VB_GENERAL, LOG_INFO,
409 QString("Grabber has capabilities: %1") .arg(capabilities));
410 }
411 }
412
413 if (hasprefmethod)
414 {
415 uint flags = kMSRunShell | kMSStdOut;
416 MythSystemLegacy grabber_method_proc(xmltv_grabber,
417 QStringList("--preferredmethod"),
418 flags);
419 grabber_method_proc.Run(15s);
420 if (grabber_method_proc.Wait() != GENERIC_EXIT_OK)
421 {
422 LOG(VB_GENERAL, LOG_ERR,
423 QString("%1 --preferredmethod failed or we timed out "
424 "waiting. You may need to upgrade your xmltv "
425 "grabber").arg(xmltv_grabber));
426 }
427 else
428 {
429 QTextStream ostream(grabber_method_proc.ReadAll());
430 (*it).xmltvgrabber_prefmethod =
431 ostream.readLine().simplified();
432
433 LOG(VB_GENERAL, LOG_INFO, QString("Grabber prefers method: %1")
434 .arg((*it).xmltvgrabber_prefmethod));
435 }
436 }
437
438 m_needPostGrabProc |= true;
439
440 if ((*it).xmltvgrabber_prefmethod == "allatonce" && !m_noAllAtOnce && !m_onlyUpdateChannels)
441 {
442 if (!GrabData(*it, 0))
443 ++failures;
444 }
445 else if ((*it).xmltvgrabber_baseline)
446 {
447
448 QDate qCurrentDate = MythDate::current().date();
449
450 // We'll keep grabbing until it returns nothing
451 // Max days currently supported is 21
452 int grabdays = REFRESH_MAX;
453
454 grabdays = (m_maxDays > 0) ? m_maxDays : grabdays;
455 grabdays = (m_onlyUpdateChannels) ? 1 : grabdays;
456
457 std::vector<bool> refresh_request;
458 refresh_request.resize(grabdays, m_refreshAll);
459 if (!m_refreshAll)
460 {
461 // Set up days to grab if all is not specified
462 // If all was specified the vector was initialized
463 // with true in all occurrences.
464 for (int i = 0; i < grabdays; i++)
465 refresh_request[i] = m_refreshDay[i];
466 }
467
468 for (int i = 0; i < grabdays; i++)
469 {
470 if (!m_fatalErrors.empty())
471 break;
472
473 // We need to check and see if the current date has changed
474 // since we started in this loop. If it has, we need to adjust
475 // the value of 'i' to compensate for this.
476 if (MythDate::current().date() != qCurrentDate)
477 {
478 QDate newDate = MythDate::current().date();
479 i += (newDate.daysTo(qCurrentDate));
480 i = std::max(i, 0);
481 qCurrentDate = newDate;
482 }
483
484 QString currDate(qCurrentDate.addDays(i).toString());
485
486 LOG(VB_GENERAL, LOG_INFO, ""); // add a space between days
487 LOG(VB_GENERAL, LOG_INFO, "Checking day @ " +
488 QString("offset %1, date: %2").arg(i).arg(currDate));
489
490 bool download_needed = false;
491
492 if (refresh_request[i])
493 {
494 if ( i == 1 )
495 {
496 LOG(VB_GENERAL, LOG_INFO,
497 "Data Refresh always needed for tomorrow");
498 }
499 else
500 {
501 LOG(VB_GENERAL, LOG_INFO,
502 "Data Refresh needed because of user request");
503 }
504 download_needed = true;
505 }
506 else
507 {
508 // Check to see if we already downloaded data for this date.
509
510 querystr = "SELECT c.chanid, COUNT(p.starttime) "
511 "FROM channel c "
512 "LEFT JOIN program p ON c.chanid = p.chanid "
513 " AND starttime >= "
514 "DATE_ADD(DATE_ADD(CURRENT_DATE(), "
515 "INTERVAL '%1' DAY), INTERVAL '20' HOUR) "
516 " AND starttime < DATE_ADD(CURRENT_DATE(), "
517 "INTERVAL '%2' DAY) "
518 "WHERE c.deleted IS NULL AND c.sourceid = %3 AND c.xmltvid != '' "
519 "GROUP BY c.chanid;";
520
521 if (query.exec(querystr.arg(i-1).arg(i).arg((*it).id)) &&
522 query.isActive())
523 {
524 int prevChanCount = 0;
525 int currentChanCount = 0;
526 int previousDayCount = 0;
527 int currentDayCount = 0;
528
529 LOG(VB_CHANNEL, LOG_INFO,
530 QString("Checking program counts for day %1")
531 .arg(i-1));
532
533 while (query.next())
534 {
535 if (query.value(1).toInt() > 0)
536 prevChanCount++;
537 previousDayCount += query.value(1).toInt();
538
539 LOG(VB_CHANNEL, LOG_INFO,
540 QString(" chanid %1 -> %2 programs")
541 .arg(query.value(0).toString())
542 .arg(query.value(1).toInt()));
543 }
544
545 if (query.exec(querystr.arg(i).arg(i+1).arg((*it).id))
546 && query.isActive())
547 {
548 LOG(VB_CHANNEL, LOG_INFO,
549 QString("Checking program counts for day %1")
550 .arg(i));
551 while (query.next())
552 {
553 if (query.value(1).toInt() > 0)
554 currentChanCount++;
555 currentDayCount += query.value(1).toInt();
556
557 LOG(VB_CHANNEL, LOG_INFO,
558 QString(" chanid %1 -> %2 programs")
559 .arg(query.value(0).toString())
560 .arg(query.value(1).toInt()));
561 }
562 }
563 else
564 {
565 LOG(VB_GENERAL, LOG_INFO,
566 QString("Data Refresh because we are unable to "
567 "query the data for day %1 to "
568 "determine if we have enough").arg(i));
569 download_needed = true;
570 }
571
572 if (currentChanCount < (prevChanCount * 0.90))
573 {
574 LOG(VB_GENERAL, LOG_INFO,
575 QString("Data refresh needed because only %1 "
576 "out of %2 channels have at least one "
577 "program listed for day @ offset %3 "
578 "from 8PM - midnight. Previous day "
579 "had %4 channels with data in that "
580 "time period.")
581 .arg(currentChanCount).arg(source_channels)
582 .arg(i).arg(prevChanCount));
583 download_needed = true;
584 }
585 else if (currentDayCount == 0)
586 {
587 LOG(VB_GENERAL, LOG_INFO,
588 QString("Data refresh needed because no data "
589 "exists for day @ offset %1 from 8PM - "
590 "midnight.").arg(i));
591 download_needed = true;
592 }
593 else if (previousDayCount == 0)
594 {
595 LOG(VB_GENERAL, LOG_INFO,
596 QString("Data refresh needed because no data "
597 "exists for day @ offset %1 from 8PM - "
598 "midnight. Unable to calculate how "
599 "much we should have for the current "
600 "day so a refresh is being forced.")
601 .arg(i-1));
602 download_needed = true;
603 }
604 else if (currentDayCount < (currentChanCount * 3))
605 {
606 LOG(VB_GENERAL, LOG_INFO,
607 QString("Data Refresh needed because offset "
608 "day %1 has less than 3 programs "
609 "per channel for the 8PM - midnight "
610 "time window for channels that "
611 "normally have data. "
612 "We want at least %2 programs, but "
613 "only found %3")
614 .arg(i).arg(currentChanCount * 3)
615 .arg(currentDayCount));
616 download_needed = true;
617 }
618 else if (currentDayCount < (previousDayCount / 2))
619 {
620 LOG(VB_GENERAL, LOG_INFO,
621 QString("Data Refresh needed because offset "
622 "day %1 has less than half the number "
623 "of programs as the previous day for "
624 "the 8PM - midnight time window. "
625 "We want at least %2 programs, but "
626 "only found %3").arg(i)
627 .arg(previousDayCount / 2)
628 .arg(currentDayCount));
629 download_needed = true;
630 }
631 }
632 else
633 {
634 LOG(VB_GENERAL, LOG_INFO,
635 QString("Data Refresh needed because we are unable "
636 "to query the data for day @ offset %1 to "
637 "determine how much we should have for "
638 "offset day %2.").arg(i-1).arg(i));
639 download_needed = true;
640 }
641 }
642
643 if (download_needed)
644 {
645 LOG(VB_GENERAL, LOG_NOTICE,
646 QString("Refreshing data for ") + currDate);
647 if (!GrabData(*it, i))
648 {
649 ++failures;
650 if (!m_fatalErrors.empty() || m_interrupted)
651 {
652 break;
653 }
654 }
655
656 if (m_endOfData)
657 {
658 LOG(VB_GENERAL, LOG_INFO,
659 "Grabber is no longer returning program data, "
660 "finishing");
661 break;
662 }
663 }
664 else
665 {
666 LOG(VB_GENERAL, LOG_NOTICE,
667 QString("Data is already present for ") + currDate +
668 ", skipping");
669 }
670 }
671 if (!m_fatalErrors.empty())
672 break;
673 }
674 else
675 {
676 LOG(VB_GENERAL, LOG_ERR,
677 QString("Grabbing XMLTV data using ") + xmltv_grabber +
678 " is not supported. You may need to upgrade to"
679 " the latest version of XMLTV.");
680 }
681
682 if (m_interrupted)
683 {
684 break;
685 }
686
687 query.prepare("SELECT MAX(endtime) FROM program p "
688 "LEFT JOIN channel c ON p.chanid=c.chanid "
689 "WHERE c.deleted IS NULL AND c.sourceid= :SRCID "
690 "AND manualid = 0 AND c.xmltvid != '';");
691 query.bindValue(":SRCID", (*it).id);
692
693 if (query.exec() && query.next())
694 {
695 if (!query.isNull(0))
696 GuideDataAfter = MythDate::fromString(query.value(0).toString());
697 }
698
699 if (GuideDataAfter == GuideDataBefore)
700 {
701 nonewdata++;
702 }
703 }
704
705 if (!m_fatalErrors.empty())
706 {
707 for (const QString& error : std::as_const(m_fatalErrors))
708 {
709 LOG(VB_GENERAL, LOG_CRIT, LOC + "Encountered Fatal Error: " + error);
710 }
711 return false;
712 }
713
715 return true;
716
717 if (failures == 0)
718 {
719 if (nonewdata > 0 &&
720 (total_sources != externally_handled))
721 {
722 status = QObject::tr(
723 "mythfilldatabase ran, but did not insert "
724 "any new data into the Guide for %1 of %2 sources. "
725 "This can indicate a potential grabber failure.")
726 .arg(nonewdata)
727 .arg(total_sources);
728 }
729 else
730 {
731 status = QObject::tr("Successful.");
732 }
733
734 updateLastRunStatus(status);
735 }
736
737 return (failures == 0);
738}
739
740/* vim: set expandtab tabstop=4 shiftwidth=4: */
std::vector< ChannelInfo > ChannelInfoList
Definition: channelinfo.h:131
void handleChannels(int id, ChannelInfoList *chanlist) const
bool m_refreshAll
Definition: filldata.h:79
QMap< uint, bool > m_refreshDay
Definition: filldata.h:78
bool m_noAllAtOnce
Definition: filldata.h:75
bool GrabData(const DataSource &source, int offset)
Definition: filldata.cpp:118
void SetRefresh(int day, bool set)
Definition: filldata.cpp:69
QStringList m_fatalErrors
Definition: filldata.h:80
QString m_grabOptions
Definition: filldata.h:66
bool m_onlyUpdateChannels
Definition: filldata.h:73
bool GrabDataFromFile(int id, const QString &filename)
Definition: filldata.cpp:87
uint m_maxDays
Definition: filldata.h:67
bool m_needPostGrabProc
Definition: filldata.h:72
bool m_interrupted
Definition: filldata.h:69
bool Run(DataSourceList &sourcelist)
Goes through the sourcelist and updates its channels with program info grabbed with the associated gr...
Definition: filldata.cpp:245
bool m_channelUpdateRun
Definition: filldata.h:74
XMLTVParser m_xmltvParser
Definition: filldata.h:64
ChannelData m_chanData
Definition: filldata.h:63
bool m_endOfData
Definition: filldata.h:70
@ kRefreshAll
Definition: filldata.h:59
@ kRefreshClear
Definition: filldata.h:58
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
bool isNull(int field) const
Definition: mythdbcon.h:219
QVariant value(int i) const
Definition: mythdbcon.h:204
bool isActive(void) const
Definition: mythdbcon.h:215
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
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
uint Wait(std::chrono::seconds timeout=0s)
QByteArray & ReadAllErr()
void Run(std::chrono::seconds timeout=0s)
Runs a command inside the /bin/sh shell. Returns immediately.
QByteArray & ReadAll()
static void HandlePrograms(uint sourceid, QMap< QString, QList< ProgInfo > > &proglist)
Called from mythfilldatabase to bulk insert data into the program database.
bool parseFile(const QString &filename, ChannelInfoList *chanlist, QMap< QString, QList< ProgInfo > > *proglist)
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
@ GENERIC_EXIT_KILLED
Process killed or stopped.
Definition: exitcodes.h:26
#define LOC
Definition: filldata.cpp:33
bool updateNextScheduledRun()
Definition: filldata.cpp:61
bool updateLastRunStatus(QString &status)
Definition: filldata.cpp:54
bool updateLastRunEnd(void)
Definition: filldata.cpp:37
bool updateLastRunStart(void)
Definition: filldata.cpp:45
static constexpr int8_t REFRESH_MAX
Definition: filldata.h:17
std::vector< DataSource > DataSourceList
Definition: filldata.h:40
unsigned int uint
Definition: freesurround.h:24
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QString GetConfDir(void)
Definition: mythdirs.cpp:263
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QString createTempFile(QString name_template, bool dir)
@ kMSStdErr
allow access to stderr
Definition: mythsystem.h:42
@ kMSStdOut
allow access to stdout
Definition: mythsystem.h:41
@ kMSRunShell
run process through shell
Definition: mythsystem.h:43
@ 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
def error(message)
Definition: smolt.py:409
QString xmltvgrabber
Definition: filldata.h:29
bool xmltvgrabber_apiconfig
Definition: filldata.h:36
QString name
Definition: filldata.h:28
int id
Definition: filldata.h:27
QString xmltvgrabber_prefmethod
Definition: filldata.h:38
static bool is_grabber_external(const QString &grabber)
Definition: videosource.h:29