MythTV  master
weatherSource.cpp
Go to the documentation of this file.
1 #include <unistd.h>
2 
3 // QT headers
4 #include <QDir>
5 #include <QFile>
6 #include <QTextStream>
7 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
8 #include <QTextCodec>
9 #else
10 #include <QStringConverter>
11 #endif
12 #include <QApplication>
13 
14 // MythTV headers
15 #include <mythcontext.h>
16 #include <mythdb.h>
17 #include <compat.h>
18 #include <mythdirs.h>
19 #include <mythsystemlegacy.h>
20 #include <exitcodes.h>
21 
22 // MythWeather headers
23 #include "weatherScreen.h"
24 #include "weatherSource.h"
25 
26 QStringList WeatherSource::ProbeTypes(const QString& workingDirectory,
27  const QString& program)
28 {
29  QStringList arguments("-t");
30  const QString loc = QString("WeatherSource::ProbeTypes(%1 %2): ")
31  .arg(program, arguments.join(" "));
32  QStringList types;
33 
34  uint flags = kMSRunShell | kMSStdOut |
36  MythSystemLegacy ms(program, arguments, flags);
37  ms.SetDirectory(workingDirectory);
38  ms.Run();
39  if (ms.Wait() != GENERIC_EXIT_OK)
40  {
41  LOG(VB_GENERAL, LOG_ERR, loc + "Cannot run script");
42  return types;
43  }
44 
45  QByteArray result = ms.ReadAll();
46  QTextStream text(result);
47 
48  while (!text.atEnd())
49  {
50  QString tmp = text.readLine();
51 
52  while (tmp.endsWith('\n') || tmp.endsWith('\r'))
53  tmp.chop(1);
54 
55  if (!tmp.isEmpty())
56  types += tmp;
57  }
58 
59  if (types.empty())
60  LOG(VB_GENERAL, LOG_ERR, loc + "Invalid output from -t option");
61 
62  return types;
63 }
64 
65 bool WeatherSource::ProbeTimeouts(const QString& workingDirectory,
66  const QString& program,
67  std::chrono::seconds &updateTimeout,
68  std::chrono::seconds &scriptTimeout)
69 {
70  QStringList arguments("-T");
71  const QString loc = QString("WeatherSource::ProbeTimeouts(%1 %2): ")
72  .arg(program, arguments.join(" "));
73 
75  scriptTimeout = DEFAULT_SCRIPT_TIMEOUT;
76 
77  uint flags = kMSRunShell | kMSStdOut |
79  MythSystemLegacy ms(program, arguments, flags);
80  ms.SetDirectory(workingDirectory);
81  ms.Run();
82  if (ms.Wait() != GENERIC_EXIT_OK)
83  {
84  LOG(VB_GENERAL, LOG_ERR, loc + "Cannot run script");
85  return false;
86  }
87 
88  QByteArray result = ms.ReadAll();
89  QTextStream text(result);
90 
91  QStringList lines;
92  while (!text.atEnd())
93  {
94  QString tmp = text.readLine();
95 
96  while (tmp.endsWith('\n') || tmp.endsWith('\r'))
97  tmp.chop(1);
98 
99  if (!tmp.isEmpty())
100  lines << tmp;
101  }
102 
103  if (lines.empty())
104  {
105  LOG(VB_GENERAL, LOG_ERR, loc + "Invalid Script Output! No Lines");
106  return false;
107  }
108 
109  QStringList temp = lines[0].split(',');
110  if (temp.size() != 2)
111  {
112  LOG(VB_GENERAL, LOG_ERR, loc +
113  QString("Invalid Script Output! '%1'").arg(lines[0]));
114  return false;
115  }
116 
117  std::array<bool,2> isOK {};
118  uint ut = temp[0].toUInt(&isOK[0]);
119  uint st = temp[1].toUInt(&isOK[1]);
120  if (!isOK[0] || !isOK[1])
121  {
122  LOG(VB_GENERAL, LOG_ERR, loc +
123  QString("Invalid Script Output! '%1'").arg(lines[0]));
124  return false;
125  }
126 
127  updateTimeout = std::chrono::seconds(ut);
128  scriptTimeout = std::chrono::seconds(st);
129 
130  return true;
131 }
132 
134 {
135  QStringList arguments("-v");
136 
137  const QString loc = QString("WeatherSource::ProbeInfo(%1 %2): ")
138  .arg(info.program, arguments.join(" "));
139 
140  uint flags = kMSRunShell | kMSStdOut |
142  MythSystemLegacy ms(info.program, arguments, flags);
143  ms.SetDirectory(info.path);
144  ms.Run();
145  if (ms.Wait() != GENERIC_EXIT_OK)
146  {
147  LOG(VB_GENERAL, LOG_ERR, loc + "Cannot run script");
148  return false;
149  }
150 
151  QByteArray result = ms.ReadAll();
152  QTextStream text(result);
153 
154  QStringList lines;
155  while (!text.atEnd())
156  {
157  QString tmp = text.readLine();
158 
159  while (tmp.endsWith('\n') || tmp.endsWith('\r'))
160  tmp.chop(1);
161 
162  if (!tmp.isEmpty())
163  lines << tmp;
164  }
165 
166  if (lines.empty())
167  {
168  LOG(VB_GENERAL, LOG_ERR, loc + "Invalid Script Output! No Lines");
169  return false;
170  }
171 
172  QStringList temp = lines[0].split(',');
173  if (temp.size() != 4)
174  {
175  LOG(VB_GENERAL, LOG_ERR, loc +
176  QString("Invalid Script Output! '%1'").arg(lines[0]));
177  return false;
178  }
179 
180  info.name = temp[0];
181  info.version = temp[1];
182  info.author = temp[2];
183  info.email = temp[3];
184 
185  return true;
186 }
187 
188 /* Basic logic of this behemouth...
189  * run script with -v flag, this returns among other things, the version number
190  * Search the database using the name (also returned from -v).
191  * if it exists, compare versions from -v and db
192  * if the same, populate the info struct from db, and we're done
193  * if they differ, get the rest of the needed information from the script and
194  * update the database, note, it does not overwrite the existing timeout values.
195  * if the script is not in the database, we probe it for types and default
196  * timeout values, and add it to the database
197  */
199 {
200  if (!fi.isReadable() || !fi.isExecutable())
201  return nullptr;
202 
203  ScriptInfo info;
204  info.path = fi.absolutePath();
205  info.program = fi.absoluteFilePath();
206 
207  if (!WeatherSource::ProbeInfo(info))
208  return nullptr;
209 
211  QString query =
212  "SELECT sourceid, source_name, update_timeout, retrieve_timeout, "
213  "path, author, version, email, types FROM weathersourcesettings "
214  "WHERE hostname = :HOST AND source_name = :NAME;";
215  db.prepare(query);
216  db.bindValue(":HOST", gCoreContext->GetHostName());
217  db.bindValue(":NAME", info.name);
218 
219  if (!db.exec())
220  {
221  LOG(VB_GENERAL, LOG_ERR, "Invalid response from database");
222  return nullptr;
223  }
224 
225  // the script exists in the db
226  if (db.next())
227  {
228  info.id = db.value(0).toInt();
229  info.updateTimeout = std::chrono::seconds(db.value(2).toUInt());
230  info.scriptTimeout = std::chrono::seconds(db.value(3).toUInt());
231 
232  // compare versions, if equal... be happy
233  QString dbver = db.value(6).toString();
234  if (dbver == info.version)
235  {
236  info.types = db.value(8).toString().split(",");
237  }
238  else
239  {
240  // versions differ, change db to match script output
241  LOG(VB_GENERAL, LOG_INFO, "New version of " + info.name + " found");
242  query = "UPDATE weathersourcesettings SET source_name = :NAME, "
243  "path = :PATH, author = :AUTHOR, version = :VERSION, "
244  "email = :EMAIL, types = :TYPES WHERE sourceid = :ID";
245  db.prepare(query);
246  // these info values were populated when getting the version number
247  // we leave the timeout values in
248  db.bindValue(":NAME", info.name);
249  db.bindValue(":PATH", info.program);
250  db.bindValue(":AUTHOR", info.author);
251  db.bindValue(":VERSION", info.version);
252 
253  // run the script to get supported data types
254  info.types = WeatherSource::ProbeTypes(info.path, info.program);
255 
256  db.bindValue(":TYPES", info.types.join(","));
257  db.bindValue(":ID", info.id);
258  db.bindValue(":EMAIL", info.email);
259  if (!db.exec())
260  {
261  MythDB::DBError("Updating weather source settings.", db);
262  return nullptr;
263  }
264  }
265  }
266  else
267  {
268  // Script is not in db, probe it and insert it into db
269  query = "INSERT INTO weathersourcesettings "
270  "(hostname, source_name, update_timeout, retrieve_timeout, "
271  "path, author, version, email, types) "
272  "VALUES (:HOST, :NAME, :UPDATETO, :RETTO, :PATH, :AUTHOR, "
273  ":VERSION, :EMAIL, :TYPES);";
274 
276  info.program,
277  info.updateTimeout,
278  info.scriptTimeout))
279  {
280  return nullptr;
281  }
282  db.prepare(query);
283  db.bindValue(":NAME", info.name);
284  db.bindValue(":HOST", gCoreContext->GetHostName());
285  db.bindValue(":UPDATETO", QString::number(info.updateTimeout.count()));
286  db.bindValue(":RETTO", QString::number(info.scriptTimeout.count()));
287  db.bindValue(":PATH", info.program);
288  db.bindValue(":AUTHOR", info.author);
289  db.bindValue(":VERSION", info.version);
290  db.bindValue(":EMAIL", info.email);
291  info.types = ProbeTypes(info.path, info.program);
292  db.bindValue(":TYPES", info.types.join(","));
293  if (!db.exec())
294  {
295  MythDB::DBError("Inserting weather source", db);
296  return nullptr;
297  }
298  query = "SELECT sourceid FROM weathersourcesettings "
299  "WHERE source_name = :NAME AND hostname = :HOST;";
300  // a little annoying, but look at what we just inserted to get the id
301  // number, not sure if we really need it, but better safe than sorry.
302  db.prepare(query);
303  db.bindValue(":HOST", gCoreContext->GetHostName());
304  db.bindValue(":NAME", info.name);
305  if (!db.exec())
306  {
307  MythDB::DBError("Getting weather sourceid", db);
308  return nullptr;
309  }
310  if (!db.next())
311  {
312  LOG(VB_GENERAL, LOG_ERR, "Error getting weather sourceid");
313  return nullptr;
314  }
315  info.id = db.value(0).toInt();
316  }
317 
318  return new ScriptInfo(info);
319 }
320 
328  : m_ready(info != nullptr),
329  m_inuse(info != nullptr),
330  m_info(info),
331  m_updateTimer(new QTimer(this))
332 {
333  QDir dir(GetConfDir());
334  if (!dir.exists("MythWeather"))
335  dir.mkdir("MythWeather");
336  dir.cd("MythWeather");
337  if (info != nullptr) {
338  if (!dir.exists(info->name))
339  dir.mkdir(info->name);
340  dir.cd(info->name);
341  }
342  m_dir = dir.absolutePath();
343 
345 }
346 
348 {
349  if (m_ms)
350  {
352  m_ms->Wait(5s);
353  delete m_ms;
354  }
355  delete m_updateTimer;
356 }
357 
359 {
360  connect(this, &WeatherSource::newData,
362  ++m_connectCnt;
363 
364  if (!m_data.empty())
365  {
366  emit newData(m_locale, m_units, m_data);
367  }
368 }
369 
371 {
372  disconnect(this, nullptr, ws, nullptr);
373  --m_connectCnt;
374 }
375 
376 QStringList WeatherSource::getLocationList(const QString &str)
377 {
378  QString program = m_info->program;
379  QStringList args;
380  args << "-l";
381  args << str;
382 
383  const QString loc = QString("WeatherSource::getLocationList(%1 %2): ")
384  .arg(program, args.join(" "));
385 
386  uint flags = kMSRunShell | kMSStdOut |
388  MythSystemLegacy ms(program, args, flags);
389  ms.SetDirectory(m_info->path);
390  ms.Run();
391 
392  if (ms.Wait() != GENERIC_EXIT_OK)
393  {
394  LOG(VB_GENERAL, LOG_ERR, loc + "Cannot run script");
395  return QStringList();
396  }
397 
398  QStringList locs;
399  QByteArray result = ms.ReadAll();
400  QTextStream text(result);
401 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
402  text.setCodec("UTF-8");
403 #else
404  text.setEncoding(QStringConverter::Utf8);
405 #endif
406  while (!text.atEnd())
407  {
408  QString tmp = text.readLine().trimmed();
409  if (!tmp.isEmpty())
410  locs << tmp;
411  }
412 
413  return locs;
414 }
415 
416 void WeatherSource::startUpdate(bool forceUpdate)
417 {
418  m_buffer.clear();
419 
421  LOG(VB_GENERAL, LOG_INFO, "Starting update of " + m_info->name);
422 
423  if (m_ms)
424  {
425  LOG(VB_GENERAL, LOG_ERR, QString("%1 process exists, skipping.")
426  .arg(m_info->name));
427  return;
428  }
429 
430  if (!forceUpdate)
431  {
432  db.prepare("SELECT updated FROM weathersourcesettings "
433  "WHERE sourceid = :ID AND "
434  "TIMESTAMPADD(SECOND,update_timeout-15,updated) > NOW()");
435  db.bindValue(":ID", getId());
436  if (db.exec() && db.size() > 0)
437  {
438  LOG(VB_GENERAL, LOG_NOTICE, QString("%1 recently updated, skipping.")
439  .arg(m_info->name));
440 
441  if (m_cachefile.isEmpty())
442  {
443  QString locale_file(m_locale);
444  locale_file.replace("/", "-");
445  m_cachefile = QString("%1/cache_%2").arg(m_dir, locale_file);
446  }
447  QFile cache(m_cachefile);
448  if (cache.exists() && cache.open( QIODevice::ReadOnly ))
449  {
450  m_buffer = cache.readAll();
451  cache.close();
452 
453  processData();
454 
455  if (m_connectCnt)
456  {
457  emit newData(m_locale, m_units, m_data);
458  }
459  return;
460  }
461  LOG(VB_GENERAL, LOG_NOTICE,
462  QString("No cachefile for %1, forcing update.")
463  .arg(m_info->name));
464  }
465  }
466 
467  m_data.clear();
468  QString program = "nice";
469  QStringList args;
470  args << m_info->program;
471  args << "-u";
472  args << (m_units == SI_UNITS ? "SI" : "ENG");
473 
474  if (!m_dir.isEmpty())
475  {
476  args << "-d";
477  args << m_dir;
478  }
479  args << m_locale;
480 
483  m_ms = new MythSystemLegacy(program, args, flags);
485 
487  this, qOverload<>(&WeatherSource::processExit));
488  connect(m_ms, &MythSystemLegacy::error,
489  this, qOverload<uint>(&WeatherSource::processExit));
490 
492 }
493 
495 {
496  startUpdate();
498 }
499 
501 {
502  m_ms->disconnect(); // disconnects all signals
503 
504  if (status == GENERIC_EXIT_OK)
505  {
506  m_buffer = m_ms->ReadAll();
507  }
508 
509  delete m_ms;
510  m_ms = nullptr;
511 
512  if (status != GENERIC_EXIT_OK)
513  {
514  LOG(VB_GENERAL, LOG_ERR, QString("script exit status %1").arg(status));
515  return;
516  }
517 
518  if (m_buffer.isEmpty())
519  {
520  LOG(VB_GENERAL, LOG_ERR, "Script returned no data");
521  return;
522  }
523 
524  if (m_cachefile.isEmpty())
525  {
526  QString locale_file(m_locale);
527  locale_file.replace("/", "-");
528  m_cachefile = QString("%1/cache_%2").arg(m_dir, locale_file);
529  }
530  QFile cache(m_cachefile);
531  if (cache.open( QIODevice::WriteOnly ))
532  {
533  cache.write(m_buffer);
534  cache.close();
535  }
536  else
537  {
538  LOG(VB_GENERAL, LOG_ERR, QString("Unable to save data to cachefile: %1")
539  .arg(m_cachefile));
540  }
541 
542  processData();
543 
545 
546  db.prepare("UPDATE weathersourcesettings "
547  "SET updated = NOW() WHERE sourceid = :ID;");
548 
549  db.bindValue(":ID", getId());
550  if (!db.exec())
551  {
552  MythDB::DBError("Updating weather source's last update time", db);
553  return;
554  }
555 
556  if (m_connectCnt)
557  {
558  emit newData(m_locale, m_units, m_data);
559  }
560 }
561 
563 {
565 }
566 
568 {
569  QString unicode_buffer = QString::fromUtf8(m_buffer);
570 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
571  QStringList data = unicode_buffer.split('\n', QString::SkipEmptyParts);
572 #else
573  QStringList data = unicode_buffer.split('\n', Qt::SkipEmptyParts);
574 #endif
575 
576  m_data.clear();
577 
578  for (int i = 0; i < data.size(); ++i)
579  {
580 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
581  QStringList temp = data[i].split("::", QString::SkipEmptyParts);
582 #else
583  QStringList temp = data[i].split("::", Qt::SkipEmptyParts);
584 #endif
585  if (temp.size() > 2)
586  LOG(VB_GENERAL, LOG_ERR, "Error parsing script file, ignoring");
587  if (temp.size() < 2)
588  {
589  LOG(VB_GENERAL, LOG_ERR,
590  QString("Unrecoverable error parsing script output %1")
591  .arg(temp.size()));
592  LOG(VB_GENERAL, LOG_ERR, QString("data[%1]: '%2'")
593  .arg(i).arg(data[i]));
594  return; // we don't emit signal
595  }
596 
597  if (temp[1] != "---")
598  {
599  if (!m_data[temp[0]].isEmpty())
600  {
601  m_data[temp[0]].append("\n" + temp[1]);
602  }
603  else
604  m_data[temp[0]] = temp[1];
605  }
606  }
607 }
608 
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
WeatherSource::m_cachefile
QString m_cachefile
Definition: weatherSource.h:97
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:124
build_compdb.args
args
Definition: build_compdb.py:11
ScriptInfo::types
QStringList types
Definition: weatherSource.h:25
DEFAULT_SCRIPT_TIMEOUT
static constexpr std::chrono::seconds DEFAULT_SCRIPT_TIMEOUT
Definition: weatherUtils.h:20
WeatherSource::ProbeTypes
static QStringList ProbeTypes(const QString &workingDirectory, const QString &program)
Definition: weatherSource.cpp:26
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:207
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
GENERIC_EXIT_OK
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
ScriptInfo::version
QString version
Definition: weatherSource.h:22
kMSDontBlockInputDevs
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:36
mythdb.h
MythSystemLegacy
Definition: mythsystemlegacy.h:67
DEFAULT_UPDATE_TIMEOUT
static constexpr std::chrono::minutes DEFAULT_UPDATE_TIMEOUT
Definition: weatherUtils.h:19
ScriptInfo::author
QString author
Definition: weatherSource.h:23
ScriptInfo::program
QString program
Definition: weatherSource.h:26
WeatherSource::m_info
ScriptInfo * m_info
Definition: weatherSource.h:93
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:197
WeatherSource::m_ms
MythSystemLegacy * m_ms
Definition: weatherSource.h:94
MythSystemLegacy::finished
void finished(void)
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
WeatherSource::m_data
DataMap m_data
Definition: weatherSource.h:102
types
static const struct wl_interface * types[]
Definition: idle_inhibit_unstable_v1.c:39
WeatherSource::disconnectScreen
void disconnectScreen(WeatherScreen *ws)
Definition: weatherSource.cpp:370
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
WeatherSource::m_connectCnt
int m_connectCnt
Definition: weatherSource.h:101
MythSystemLegacy::ReadAll
QByteArray & ReadAll()
Definition: mythsystemlegacy.cpp:398
WeatherSource::startUpdateTimer
void startUpdateTimer()
Definition: weatherSource.h:69
mythdirs.h
weatherSource.h
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
mythsystemlegacy.h
WeatherSource::m_locale
QString m_locale
Definition: weatherSource.h:96
MythSystemLegacy::Signal
void Signal(MythSignal sig)
Definition: mythsystemlegacy.cpp:295
WeatherScreen::newData
virtual void newData(const QString &, units_t, DataMap data)
Definition: weatherScreen.cpp:72
WeatherSource::ProbeInfo
static bool ProbeInfo(ScriptInfo &scriptInfo)
Definition: weatherSource.cpp:133
WeatherSource::processData
void processData()
Definition: weatherSource.cpp:567
WeatherSource::m_buffer
QByteArray m_buffer
Definition: weatherSource.h:98
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:224
WeatherSource::newData
void newData(QString, units_t, DataMap)
WeatherSource::processExit
void processExit()
Definition: weatherSource.cpp:562
SI_UNITS
#define SI_UNITS
Definition: weatherUtils.h:17
MythSystemLegacy::error
void error(uint status)
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
compat.h
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:200
WeatherSource::updateTimeout
void updateTimeout()
Definition: weatherSource.cpp:494
MythSystemLegacy::Wait
uint Wait(std::chrono::seconds timeout=0s)
Definition: mythsystemlegacy.cpp:242
WeatherSource::ProbeTimeouts
static bool ProbeTimeouts(const QString &workingDirectory, const QString &program, std::chrono::seconds &updateTimeout, std::chrono::seconds &scriptTimeout)
Definition: weatherSource.cpp:65
WeatherSource::m_updateTimer
QTimer * m_updateTimer
Definition: weatherSource.h:100
MythSystemLegacy::SetDirectory
void SetDirectory(const QString &directory)
Definition: mythsystemlegacy.cpp:187
WeatherScreen
Weather screen.
Definition: weatherScreen.h:26
uint
unsigned int uint
Definition: compat.h:140
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
WeatherSource::WeatherSource
WeatherSource(ScriptInfo *info)
Watch out, we store the parameter as a member variable, don't go deleting it, that wouldn't be good.
Definition: weatherSource.cpp:327
kMSRunShell
@ kMSRunShell
run process through shell
Definition: mythsystem.h:43
WeatherSource::m_dir
QString m_dir
Definition: weatherSource.h:95
kMSRunBackground
@ kMSRunBackground
run child in the background
Definition: mythsystem.h:38
ScriptInfo::scriptTimeout
std::chrono::seconds scriptTimeout
Definition: weatherSource.h:28
kSignalKill
@ kSignalKill
Definition: mythsystem.h:64
ScriptInfo::email
QString email
Definition: weatherSource.h:24
WeatherSource::getId
int getId()
Definition: weatherSource.h:75
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:893
WeatherSource::m_units
units_t m_units
Definition: weatherSource.h:99
mythcontext.h
WeatherSource::startUpdate
void startUpdate(bool forceUpdate=false)
Definition: weatherSource.cpp:416
ScriptInfo::updateTimeout
std::chrono::seconds updateTimeout
Definition: weatherSource.h:29
WeatherSource::connectScreen
void connectScreen(WeatherScreen *ws)
Definition: weatherSource.cpp:358
ScriptInfo::name
QString name
Definition: weatherSource.h:21
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:862
weatherScreen.h
WeatherSource::ProbeScript
static ScriptInfo * ProbeScript(const QFileInfo &fi)
Definition: weatherSource.cpp:198
MythSystemLegacy::Run
void Run(std::chrono::seconds timeout=0s)
Runs a command inside the /bin/sh shell. Returns immediately.
Definition: mythsystemlegacy.cpp:212
WeatherSource::~WeatherSource
~WeatherSource() override
Definition: weatherSource.cpp:347
kMSDontDisableDrawing
@ kMSDontDisableDrawing
avoid disabling UI drawing
Definition: mythsystem.h:37
ScriptInfo
Definition: serverSideScripting.h:36
exitcodes.h
kMSStdOut
@ kMSStdOut
allow access to stdout
Definition: mythsystem.h:41
ScriptInfo::path
QString path
Definition: weatherSource.h:27
WeatherSource::getLocationList
QStringList getLocationList(const QString &str)
Definition: weatherSource.cpp:376
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
ScriptInfo::id
int id
Definition: weatherSource.h:30