MythTV master
backendhousekeeper.cpp
Go to the documentation of this file.
1// POSIX headers
2#include <unistd.h>
3#include <sys/types.h>
4
5// ANSI C headers
6#include <algorithm>
7#include <cstdlib>
8
9// Qt headers
10#include <QDateTime>
11#include <QDir>
12#include <QFileInfo>
13#include <QRegularExpression>
14#include <QStringList>
15
16// MythTV headers
19#include "libmythbase/mythdb.h"
24#include "libmythbase/mythversion.h"
30#include "libmythtv/jobqueue.h"
31
32// MythBackend
33#include "backendhousekeeper.h"
34
35static constexpr int64_t kFourHours {4LL * 60 * 60};
36
38{
46 return true;
47}
48
50{
52
53 query.prepare("DELETE FROM inuseprograms "
54 "WHERE hostname = :HOSTNAME AND "
55 "( recusage = 'recorder' OR recusage LIKE 'Unknown %' );");
56 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
57 if (!query.exec())
58 MythDB::DBError("CleanupTask::CleanupOldRecordings", query);
59}
60
62{
63 QDateTime fourHoursAgo = MythDate::current().addSecs(-kFourHours);
65
66 query.prepare("DELETE FROM inuseprograms "
67 "WHERE lastupdatetime < :FOURHOURSAGO ;");
68 query.bindValue(":FOURHOURSAGO", fourHoursAgo);
69 if (!query.exec())
70 MythDB::DBError("CleanupTask::CleanupInUsePrograms", query);
71}
72
74{
75 QDateTime fourHoursAgo = MythDate::current().addSecs(-kFourHours);
77 MSqlQuery deleteQuery(MSqlQuery::InitCon());
78
79 // Keep these tvchains, they may be in use.
80 query.prepare("SELECT DISTINCT chainid FROM tvchain "
81 "WHERE endtime > :FOURHOURSAGO ;");
82 query.bindValue(":FOURHOURSAGO", fourHoursAgo);
83
84 if (!query.exec() || !query.isActive())
85 {
86 MythDB::DBError("HouseKeeper Cleaning TVChain Table", query);
87 return;
88 }
89
90 QString msg;
91 QString keepChains;
92 while (query.next())
93 {
94 if (keepChains.isEmpty())
95 keepChains = "'" + query.value(0).toString() + "'";
96 else
97 keepChains += ", '" + query.value(0).toString() + "'";
98 }
99
100 if (keepChains.isEmpty())
101 msg = "DELETE FROM tvchain WHERE endtime < now();";
102 else
103 {
104 msg = QString("DELETE FROM tvchain "
105 "WHERE chainid NOT IN ( %1 ) AND endtime < now();")
106 .arg(keepChains);
107 }
108 deleteQuery.prepare(msg);
109 if (!deleteQuery.exec())
110 MythDB::DBError("CleanupTask::CleanupOrphanedLiveTV", deleteQuery);
111}
112
114{
116 MSqlQuery deleteQuery(MSqlQuery::InitCon());
117 // tables[tableIndex][0] is the table name
118 // tables[tableIndex][1] is the name of the column on which the join is
119 // performed
120 std::array<std::array<QString,2>,5> tables {{
121 { "recordedprogram", "progstart" },
122 { "recordedrating", "progstart" },
123 { "recordedcredits", "progstart" },
124 { "recordedmarkup", "starttime" },
125 { "recordedseek", "starttime" },
126 }};
127
128 // Because recordedseek can have millions of rows, we don't want to JOIN it
129 // with recorded. Instead, pull out DISTINCT chanid and starttime into a
130 // temporary table (resulting in tens, hundreds, or--at most--a few
131 // thousand rows) for the JOIN
132 QString querystr;
133 querystr = "CREATE TEMPORARY TABLE IF NOT EXISTS temprecordedcleanup ( "
134 "chanid int(10) unsigned NOT NULL default '0', "
135 "starttime datetime NOT NULL default '0000-00-00 00:00:00' "
136 ");";
137
138 if (!query.exec(querystr))
139 {
140 MythDB::DBError("CleanupTask::CleanupRecordedTables"
141 "(creating temporary table)", query);
142 return;
143 }
144
145 for (const auto & [table,column] : tables)
146 {
147 query.prepare(QString("TRUNCATE TABLE temprecordedcleanup;"));
148 if (!query.exec() || !query.isActive())
149 {
150 MythDB::DBError("CleanupTask::CleanupRecordedTables"
151 "(truncating temporary table)", query);
152 return;
153 }
154
155 query.prepare(QString("INSERT INTO temprecordedcleanup "
156 "( chanid, starttime ) "
157 "SELECT DISTINCT chanid, starttime "
158 "FROM %1;")
159 .arg(table));
160
161 if (!query.exec() || !query.isActive())
162 {
163 MythDB::DBError("CleanupTask::CleanupRecordedTables"
164 "(cleaning recorded tables)", query);
165 return;
166 }
167
168 query.prepare(QString("SELECT DISTINCT p.chanid, p.starttime "
169 "FROM temprecordedcleanup p "
170 "LEFT JOIN recorded r "
171 "ON p.chanid = r.chanid "
172 "AND p.starttime = r.%1 "
173 "WHERE r.chanid IS NULL;").arg(column));
174 if (!query.exec() || !query.isActive())
175 {
176 MythDB::DBError("CleanupTask::CleanupRecordedTables"
177 "(cleaning recorded tables)", query);
178 return;
179 }
180
181 deleteQuery.prepare(QString("DELETE FROM %1 "
182 "WHERE chanid = :CHANID "
183 "AND starttime = :STARTTIME;")
184 .arg(table));
185 while (query.next())
186 {
187 deleteQuery.bindValue(":CHANID", query.value(0).toString());
188 deleteQuery.bindValue(":STARTTIME", query.value(1));
189 if (!deleteQuery.exec())
190 {
191 MythDB::DBError("CleanupTask::CleanupRecordedTables"
192 "(cleaning recorded tables)", deleteQuery);
193 return;
194 }
195 }
196 }
197
198 if (!query.exec("DROP TABLE temprecordedcleanup;"))
199 MythDB::DBError("CleanupTask::CleanupRecordedTables"
200 "(deleting temporary table)", query);
201}
202
204{
206 MSqlQuery deleteQuery(MSqlQuery::InitCon());
207
208 // Delete all channels from the database that have already
209 // been deleted for at least one day and that are not referenced
210 // anymore by a recording.
211 query.prepare(QString("DELETE channel "
212 "FROM channel "
213 "LEFT JOIN recorded r "
214 " ON r.chanid = channel.chanid "
215 "LEFT JOIN oldrecorded o "
216 " ON o.chanid = channel.chanid "
217 "WHERE channel.deleted IS NOT NULL "
218 " AND channel.deleted < "
219 " DATE_SUB(NOW(), INTERVAL 1 DAY) "
220 " AND r.chanid IS NULL "
221 " AND o.chanid IS NULL"));
222 if (!query.exec())
223 MythDB::DBError("CleanupTask::CleanupChannelTables "
224 "(channel table)", query);
225
226 // Delete all multiplexes from the database that are not
227 // referenced anymore by a channel.
228 query.prepare(QString("DELETE dtv_multiplex "
229 "FROM dtv_multiplex "
230 "LEFT JOIN channel c "
231 " ON c.mplexid = dtv_multiplex.mplexid "
232 "WHERE c.chanid IS NULL"));
233 if (!query.exec())
234 MythDB::DBError("CleanupTask::CleanupChannelTables "
235 "(dtv_multiplex table)", query);
236
237 // Delete all IPTV channel data extension records from the database
238 // when the channel it refers to does not exist anymore.
239 query.prepare(QString("DELETE iptv_channel "
240 "FROM iptv_channel "
241 "LEFT JOIN channel c "
242 " ON c.chanid = iptv_channel.chanid "
243 "WHERE c.chanid IS NULL"));
244 if (!query.exec())
245 MythDB::DBError("CleanupTask::CleanupChannelTables "
246 "(iptv_channel table)", query);
247}
248
250{
252 // Keep as many days of listings data as we keep matching, non-recorded
253 // oldrecorded entries to allow for easier post-mortem analysis
254 int offset = gCoreContext->GetNumSetting( "CleanOldRecorded", 10);
255 // Also make sure to keep enough data so that we can flag the original
256 // airdate, for when that isn't included in guide data
257 int newEpiWindow = gCoreContext->GetNumSetting( "NewEpisodeWindow", 14);
258 offset = std::max(newEpiWindow, offset);
259
260 query.prepare("DELETE FROM oldprogram WHERE airdate < "
261 "DATE_SUB(CURRENT_DATE, INTERVAL 320 DAY);");
262 if (!query.exec())
263 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
264
265 query.prepare("REPLACE INTO oldprogram (oldtitle,airdate) "
266 "SELECT title,starttime FROM program "
267 "WHERE starttime < NOW() AND manualid = 0 "
268 "GROUP BY title;");
269 if (!query.exec())
270 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
271
272 query.prepare("DELETE FROM program WHERE starttime <= "
273 "DATE_SUB(CURRENT_DATE, INTERVAL :OFFSET DAY);");
274 query.bindValue(":OFFSET", offset);
275 if (!query.exec())
276 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
277
278 query.prepare("DELETE FROM programrating WHERE starttime <= "
279 "DATE_SUB(CURRENT_DATE, INTERVAL :OFFSET DAY);");
280 query.bindValue(":OFFSET", offset);
281 if (!query.exec())
282 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
283
284 query.prepare("DELETE FROM programgenres WHERE starttime <= "
285 "DATE_SUB(CURRENT_DATE, INTERVAL :OFFSET DAY);");
286 query.bindValue(":OFFSET", offset);
287 if (!query.exec())
288 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
289
290 query.prepare("DELETE FROM credits WHERE starttime <= "
291 "DATE_SUB(CURRENT_DATE, INTERVAL :OFFSET DAY);");
292 query.bindValue(":OFFSET", offset);
293 if (!query.exec())
294 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
295
296 query.prepare("DELETE FROM record WHERE (type = :SINGLE "
297 "OR type = :OVERRIDE OR type = :DONTRECORD) "
298 "AND enddate < CURDATE();");
299 query.bindValue(":SINGLE", kSingleRecord);
300 query.bindValue(":OVERRIDE", kOverrideRecord);
301 query.bindValue(":DONTRECORD", kDontRecord);
302 if (!query.exec())
303 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
304
306 findq.prepare("SELECT record.recordid FROM record "
307 "LEFT JOIN oldfind ON oldfind.recordid = record.recordid "
308 "WHERE type = :FINDONE AND oldfind.findid IS NOT NULL;");
309 findq.bindValue(":FINDONE", kOneRecord);
310
311 if (findq.exec())
312 {
313 query.prepare("DELETE FROM record WHERE recordid = :RECORDID;");
314 while (findq.next())
315 {
316 query.bindValue(":RECORDID", findq.value(0).toInt());
317 if (!query.exec())
318 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
319 }
320 }
321 query.prepare("DELETE FROM oldfind WHERE findid < TO_DAYS(NOW()) - 14;");
322 if (!query.exec())
323 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
324
325 query.prepare("DELETE FROM oldrecorded WHERE "
326 "recstatus <> :RECORDED AND duplicate = 0 AND "
327 "endtime < DATE_SUB(CURRENT_DATE, INTERVAL :CLEAN DAY);");
328 query.bindValue(":RECORDED", RecStatus::Recorded);
329 query.bindValue(":CLEAN", offset);
330 if (!query.exec())
331 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
332}
333
334bool ThemeUpdateTask::DoCheckRun(const QDateTime& now)
335{
336 return gCoreContext->GetBoolSetting("ThemeUpdateNofications", true) &&
338}
339
341{
342 uint major { 0 };
343 uint minor { 0 };
344 bool devel { false };
345 bool parsed = ParseMythSourceVersion(devel, major, minor);
346 bool result = false;
347
348 if (!parsed || devel)
349 {
350 LOG(VB_GENERAL, LOG_INFO, QString("Loading themes for devel"));
351 result |= LoadVersion("trunk", LOG_ERR);
352 }
353 else
354 {
355 LOG(VB_GENERAL, LOG_INFO, QString("Loading themes for %1").arg(major));
356 result |= LoadVersion(QString::number(major), LOG_ERR);
357
358 for (int i = minor ; i > 0; i--)
359 {
360 QString majmin = QString("%1.%2").arg(major).arg(i);
361 LOG(VB_GENERAL, LOG_INFO,
362 QString("Loading themes for %1").arg(majmin));
363 result |= LoadVersion(majmin, LOG_INFO);
364 }
365 }
366 return result;
367}
368
369bool ThemeUpdateTask::LoadVersion(const QString &version, int download_log_level)
370{
371 QString remoteThemesDir = GetConfDir();
372 remoteThemesDir.append("/tmp/remotethemes");
373
374 QDir dir(remoteThemesDir);
375 if (!dir.exists() && !dir.mkpath(remoteThemesDir))
376 {
377 LOG(VB_GENERAL, LOG_ERR,
378 QString("HouseKeeper: Error creating %1 "
379 "directory for remote themes info cache.")
380 .arg(remoteThemesDir));
381 return false;
382 }
383
384 QString remoteThemesFile = remoteThemesDir;
385 remoteThemesFile.append("/themes.zip");
386
387 m_url = QString("%1/%2/themes.zip")
388 .arg(gCoreContext->GetSetting("ThemeRepositoryURL",
389 "http://themes.mythtv.org/themes/repository"),
390 version);
391
392 m_running = true;
393 bool result = GetMythDownloadManager()->download(m_url, remoteThemesFile);
394 m_running = false;
395
396 if (!result)
397 {
398 LOG(VB_GENERAL, (LogLevel_t)download_log_level,
399 QString("HouseKeeper: Failed to download %1 "
400 "remote themes info package.").arg(m_url));
401 return false;
402 }
403
404 if (!extractZIP(remoteThemesFile, remoteThemesDir))
405 {
406 LOG(VB_GENERAL, LOG_ERR,
407 QString("HouseKeeper: Error extracting %1 "
408 "remote themes info package.").arg(remoteThemesFile));
409 QFile::remove(remoteThemesFile);
410 return false;
411 }
412
413 return true;
414}
415
417{
418 if (m_running)
420 m_running = false;
421}
422
424 : DailyHouseKeeperTask("UpdateRadioStreams", kHKGlobal, kHKRunOnStartup)
425{
426}
427
429{
430 if (m_msMU)
431 {
432 // this should never be defined, but terminate it anyway
434 m_msMU->Term(true);
435 delete m_msMU;
436 m_msMU = nullptr;
437 }
438
439 QString command = GetAppBinDir() + "mythutil";
440 QStringList args;
441 args << "--updateradiostreams";
443
444 LOG(VB_GENERAL, LOG_INFO, QString("Performing Radio Streams Update: %1 %2")
445 .arg(command, args.join(" ")));
446
448
449 m_msMU->Run();
450 uint result = m_msMU->Wait();
451
452 delete m_msMU;
453 m_msMU = nullptr;
454
455 if (result != GENERIC_EXIT_OK)
456 {
457 LOG(VB_GENERAL, LOG_ERR, QString("Update Radio Streams command '%1' failed")
458 .arg(command));
459 return false;
460 }
461
462 LOG(VB_GENERAL, LOG_INFO, QString("Radio Streams Update Complete"));
463 return true;
464}
465
467{
468 delete m_msMU;
469 m_msMU = nullptr;
470}
471
472bool RadioStreamUpdateTask::DoCheckRun(const QDateTime& now)
473{
474 // we are only interested in the global setting so remove any local host setting just in case
475 QString setting = GetMythDB()->GetSettingOnHost("MusicStreamListModified", gCoreContext->GetHostName(), "");
476 if (!setting.isEmpty())
477 {
478 GetMythDB()->ClearSetting("MusicStreamListModified");
479 }
480
481 // check we are not already running a radio stream update
482 return gCoreContext->GetSetting("MusicStreamListModified") == "Updating" &&
484}
485
487{
489 // just kill it, the runner thread will handle any necessary cleanup
490 m_msMU->Term(true);
491}
492
494 : DailyHouseKeeperTask("RecordedArtworkUpdate", kHKGlobal, kHKRunOnStartup)
495{
496}
497
499{
500 if (m_msMML)
501 {
502 // this should never be defined, but terminate it anyway
504 m_msMML->Term(true);
505 delete m_msMML;
506 m_msMML = nullptr;
507 }
508
509 QString command = GetAppBinDir() + "mythmetadatalookup";
510 QStringList args;
511 args << "--refresh-all-artwork";
513
514 LOG(VB_GENERAL, LOG_INFO, QString("Performing Artwork Refresh: %1 %2")
515 .arg(command, args.join(" ")));
516
518
519 m_msMML->Run();
520 uint result = m_msMML->Wait();
521
522 delete m_msMML;
523 m_msMML = nullptr;
524
525 if (result != GENERIC_EXIT_OK)
526 {
527 LOG(VB_GENERAL, LOG_ERR, QString("Artwork command '%1' failed")
528 .arg(command));
529 return false;
530 }
531 LOG(VB_GENERAL, LOG_INFO, QString("Artwork Refresh Complete"));
532 return true;
533}
534
536{
537 delete m_msMML;
538 m_msMML = nullptr;
539}
540
541bool ArtworkTask::DoCheckRun(const QDateTime& now)
542{
543 return gCoreContext->GetBoolSetting("DailyArtworkUpdates", false) &&
545}
546
548{
550 // just kill it, the runner thread will handle any necessary cleanup
551 m_msMML->Term(true);
552}
553
555{
557 return true;
558}
559
561 DailyHouseKeeperTask("MythFillDB")
562{
564}
565
567{
568 // we need to set the time window from database settings, so we cannot
569 // initialize these values in. grab them and set them afterwards
570 auto min = gCoreContext->GetDurSetting<std::chrono::hours>("MythFillMinHour", -1h);
571 auto max = gCoreContext->GetDurSetting<std::chrono::hours>("MythFillMaxHour", 23h);
572
573 if (min == -1h)
574 {
575 min = 0h;
576 max = 23h;
577 }
578 else
579 {
580 // make sure they fall within the range of 0-23
581 min %= 24;
582 max %= 24;
583 }
584
586}
587
589{
590// if (!gCoreContext->GetBoolSetting("MythFillGrabberSuggestsTime", true))
591// // this feature is disabled, so don't bother with a deeper check
592// return false;
593//
594// MSqlQuery result(MSqlQuery::InitCon());
595// if (result.isConnected())
596// {
597// // check to see if we have any of a list of supported grabbers in use
598// // TODO: this is really cludgy. there has to be a better way to test
599// result.prepare("SELECT COUNT(*) FROM videosource"
600// " WHERE xmltvgrabber IN"
601// " ( 'technovera' );");
602// if ((result.exec()) &&
603// (result.next()) &&
604// (result.value(0).toInt() > 0))
605// return true;
606// }
607
608 return gCoreContext->GetBoolSetting("MythFillGrabberSuggestsTime", true);
609}
610
611bool MythFillDatabaseTask::DoCheckRun(const QDateTime& now)
612{
613 if (!gCoreContext->GetBoolSetting("MythFillEnabled", true))
614 {
615 // we don't want to run this manually, so abort early
616 LOG(VB_GENERAL, LOG_DEBUG, "MythFillDatabase is disabled. Cannot run.");
617 return false;
618 }
619
620// if (m_running)
621// // we're still running from the previous pass, so abort early
622// return false;
623
624 if (UseSuggestedTime())
625 {
626 QDateTime nextRun = MythDate::fromString(
627 gCoreContext->GetSetting("MythFillSuggestedRunTime",
628 "1970-01-01T00:00:00"));
629 LOG(VB_GENERAL, LOG_DEBUG,
630 QString("MythFillDatabase scheduled to run at %1.")
631 .arg(nextRun.toString()));
632
633 // Delete the cached value immediately. Necessary because the
634 // value is written/read by different applications.
635 GetMythDB()->ClearSettingsCache("MythFillSuggestedRunTime");
636
637 // is it yet time
638 return nextRun <= now;
639 }
640 if (InWindow(now))
641 // we're inside our permitted window
642 return true;
643
644 // just let DailyHouseKeeperTask handle things
645 LOG(VB_GENERAL, LOG_DEBUG, "Performing daily run check.");
647}
648
650{
651 if (m_msMFD)
652 {
653 // this should never be defined, but terminate it anyway
655 m_msMFD->Term(true);
656 delete m_msMFD;
657 m_msMFD = nullptr;
658 }
659
660 QString mfpath = gCoreContext->GetSetting("MythFillDatabasePath",
661 "mythfilldatabase");
662 QString mfarg = gCoreContext->GetSetting("MythFillDatabaseArgs", "");
663
665 if (mfpath == "mythfilldatabase")
666 {
668 mfpath = GetAppBinDir() + "mythfilldatabase";
669 }
670
671 QString cmd = QString("%1 %2").arg(mfpath, mfarg);
672
673 m_msMFD = new MythSystemLegacy(cmd, opts);
674
675 m_msMFD->Run();
676 uint result = m_msMFD->Wait();
677
678 delete m_msMFD;
679 m_msMFD = nullptr;
680
681 if (result != GENERIC_EXIT_OK)
682 {
683 LOG(VB_GENERAL, LOG_ERR, QString("MythFillDatabase command '%1' failed")
684 .arg(cmd));
685 return false;
686 }
687
688 return true;
689}
690
692{
693 delete m_msMFD;
694 m_msMFD = nullptr;
695}
696
698{
700 // just kill it, the runner thread will handle any necessary cleanup
701 m_msMFD->Term(true);
702}
static constexpr int64_t kFourHours
void Terminate(void) override
~ArtworkTask(void) override
MythSystemLegacy * m_msMML
bool DoCheckRun(const QDateTime &now) override
bool DoRun(void) override
static void CleanupChannelTables(void)
static void CleanupProgramListings(void)
static void CleanupRecordedTables(void)
static void CleanupInUsePrograms(void)
bool DoRun(void) override
static void CleanupOrphanedLiveTV(void)
static void CleanupOldRecordings(void)
Modified PeriodicHouseKeeperTask for tasks to be run once daily.
Definition: housekeeper.h:109
virtual void SetHourWindow(std::chrono::hours min, std::chrono::hours max)
bool InWindow(const QDateTime &now) override
bool DoRun(void) override
static void CleanupOldJobsInQueue()
Definition: jobqueue.cpp:1635
static void RecoverOldJobsInQueue()
Definition: jobqueue.h:213
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
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
QString GetHostName(void)
QString GetSetting(const QString &key, const QString &defaultval="")
int GetNumSetting(const QString &key, int defaultval=0)
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
bool GetBoolSetting(const QString &key, bool defaultval=false)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
void cancelDownload(const QString &url, bool block=true)
Cancel a queued or current download.
bool download(const QString &url, const QString &dest, bool reload=false)
Downloads a URL to a file in blocking mode.
bool DoRun(void) override
MythSystemLegacy * m_msMFD
~MythFillDatabaseTask(void) override
bool DoCheckRun(const QDateTime &now) override
void Terminate(void) override
static bool UseSuggestedTime(void)
uint Wait(std::chrono::seconds timeout=0s)
uint GetStatus(void) const
void Term(bool force=false)
void Run(std::chrono::seconds timeout=0s)
Runs a command inside the /bin/sh shell. Returns immediately.
bool DoCheckRun(const QDateTime &now) override
bool DoCheckRun(const QDateTime &now) override
bool DoRun(void) override
~RadioStreamUpdateTask(void) override
void Terminate(void) override
MythSystemLegacy * m_msMU
bool LoadVersion(const QString &version, int download_log_level)
bool DoRun(void) override
bool DoCheckRun(const QDateTime &now) override
void Terminate(void) override
#define minor(X)
Definition: compat.h:74
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
@ GENERIC_EXIT_RUNNING
Process is running.
Definition: exitcodes.h:28
unsigned int uint
Definition: freesurround.h:24
@ kHKGlobal
task should only run once per cluster e.g.
Definition: housekeeper.h:26
@ kHKRunOnStartup
task is queued when HouseKeeper is started
Definition: housekeeper.h:36
QString logPropagateArgs
Definition: logging.cpp:82
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDB * GetMythDB(void)
Definition: mythdb.cpp:51
QString GetAppBinDir(void)
Definition: mythdirs.cpp:260
QString GetConfDir(void)
Definition: mythdirs.cpp:263
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
@ kMSPropagateLogs
add arguments for MythTV log propagation
Definition: mythsystem.h:52
@ kMSRunShell
run process through shell
Definition: mythsystem.h:43
@ kMSAutoCleanup
automatically delete if backgrounded
Definition: mythsystem.h:45
bool ParseMythSourceVersion(bool &devel, uint &major, uint &minor, const char *version)
Definition: mythversion.cpp:26
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
string version
Definition: giantbomb.py:185
@ kOneRecord
@ kOverrideRecord
@ kSingleRecord
@ kDontRecord
bool extractZIP(QString zipFile, const QString &outDir)
Definition: unziputil.cpp:17