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