00001
00002 #include <unistd.h>
00003 #include <sys/types.h>
00004 #include <unistd.h>
00005
00006
00007 #include <cstdlib>
00008
00009
00010 #include <iostream>
00011 using namespace std;
00012
00013
00014 #include <QStringList>
00015 #include <QDateTime>
00016 #include <QDir>
00017 #include <QFileInfo>
00018
00019
00020 #include "housekeeper.h"
00021 #include "jobqueue.h"
00022 #include "mythcorecontext.h"
00023 #include "mythdb.h"
00024 #include "mythmiscutil.h"
00025 #include "compat.h"
00026 #include "mythdirs.h"
00027 #include "programinfo.h"
00028 #include "eitcache.h"
00029 #include "scheduler.h"
00030 #include "mythcoreutil.h"
00031 #include "mythdownloadmanager.h"
00032 #include "exitcodes.h"
00033 #include "mythversion.h"
00034 #include "mythlogging.h"
00035
00036 void HouseKeepingThread::run(void)
00037 {
00038 RunProlog();
00039 m_parent->RunHouseKeeping();
00040 RunEpilog();
00041 }
00042
00043 void MythFillDatabaseThread::run(void)
00044 {
00045 RunProlog();
00046 m_parent->RunMFD();
00047 RunEpilog();
00048 }
00049
00050 HouseKeeper::HouseKeeper(bool runthread, bool master, Scheduler *lsched) :
00051 isMaster(master), sched(lsched),
00052 houseKeepingRun(runthread), houseKeepingThread(NULL),
00053 fillDBThread(NULL), fillDBStarted(false),
00054 fillDBMythSystem(NULL)
00055 {
00056 CleanupMyOldRecordings();
00057
00058 if (runthread)
00059 {
00060 houseKeepingThread = new HouseKeepingThread(this);
00061 houseKeepingThread->start();
00062
00063 QMutexLocker locker(&houseKeepingLock);
00064 while (houseKeepingRun && !houseKeepingThread->isRunning())
00065 houseKeepingWait.wait(locker.mutex());
00066 }
00067 }
00068
00069 HouseKeeper::~HouseKeeper()
00070 {
00071 if (houseKeepingThread)
00072 {
00073 {
00074 QMutexLocker locker(&houseKeepingLock);
00075 houseKeepingRun = false;
00076 houseKeepingWait.wakeAll();
00077 }
00078 houseKeepingThread->wait();
00079 delete houseKeepingThread;
00080 houseKeepingThread = NULL;
00081 }
00082
00083 if (fillDBThread)
00084 {
00085 KillMFD();
00086 delete fillDBThread;
00087 fillDBThread = NULL;
00088 }
00089 }
00090
00091 bool HouseKeeper::wantToRun(const QString &dbTag, int period, int minhour,
00092 int maxhour, bool nowIfPossible)
00093 {
00094 bool runOK = false;
00095 unsigned int oneday = 60 * 60 * 24;
00096 int longEnough = 0;
00097
00098 if (period)
00099 longEnough = ((period * oneday) - oneday/2);
00100 else
00101 longEnough = oneday / 8;
00102
00103 QDateTime now = QDateTime::currentDateTime();
00104 QDateTime lastrun;
00105 lastrun.setTime_t(0);
00106
00107 if (minhour < 0)
00108 minhour = 0;
00109 if (maxhour > 23)
00110 maxhour = 23;
00111
00112 MSqlQuery result(MSqlQuery::InitCon());
00113 if (result.isConnected())
00114 {
00115 result.prepare("SELECT lastrun FROM housekeeping WHERE tag = :TAG ;");
00116 result.bindValue(":TAG", dbTag);
00117
00118 if (result.exec() && result.next())
00119 {
00120 lastrun = result.value(0).toDateTime();
00121
00122 if ((lastrun.secsTo(now) > longEnough) &&
00123 (now.date().day() != lastrun.date().day()))
00124 {
00125 int hour = now.time().hour();
00126
00127 if (((minhour > maxhour) &&
00128 ((hour <= maxhour) || (hour >= minhour))) ||
00129 ((hour >= minhour) && (hour <= maxhour)))
00130 {
00131 int minute = now.time().minute();
00132
00133
00134
00135
00136
00137
00138
00139
00140 if ((nowIfPossible) ||
00141 (hour == maxhour && minute > 30) ||
00142 ((random()%((((24+maxhour-hour)%24)*12+(60-minute)/5 - 6) + 1)) == 0))
00143 runOK = true;
00144 }
00145 }
00146 }
00147 else
00148 {
00149 result.prepare("INSERT INTO housekeeping(tag,lastrun) "
00150 "values(:TAG ,now());");
00151 result.bindValue(":TAG", dbTag);
00152 if (!result.exec())
00153 MythDB::DBError("HouseKeeper::wantToRun -- insert", result);
00154
00155 runOK = true;
00156 }
00157 }
00158
00159 return runOK;
00160 }
00161
00162 void HouseKeeper::updateLastrun(const QString &dbTag)
00163 {
00164 MSqlQuery result(MSqlQuery::InitCon());
00165 if (result.isConnected())
00166 {
00167 result.prepare("DELETE FROM housekeeping WHERE tag = :TAG ;");
00168 result.bindValue(":TAG", dbTag);
00169 if (!result.exec())
00170 MythDB::DBError("HouseKeeper::updateLastrun -- delete", result);
00171
00172 result.prepare("INSERT INTO housekeeping(tag,lastrun) "
00173 "values(:TAG ,now()) ;");
00174 result.bindValue(":TAG", dbTag);
00175 if (!result.exec())
00176 MythDB::DBError("HouseKeeper::updateLastrun -- insert", result);
00177 }
00178 }
00179
00180 QDateTime HouseKeeper::getLastRun(const QString &dbTag)
00181 {
00182 QDateTime lastRun;
00183 MSqlQuery result(MSqlQuery::InitCon());
00184
00185 lastRun.setTime_t(0);
00186
00187 result.prepare("SELECT lastrun FROM housekeeping WHERE tag = :TAG ;");
00188 result.bindValue(":TAG", dbTag);
00189
00190 if (result.exec() && result.next())
00191 {
00192 lastRun = result.value(0).toDateTime();
00193 }
00194
00195 return lastRun;
00196 }
00197
00198 void HouseKeeper::RunHouseKeeping(void)
00199 {
00200
00201 {
00202 QMutexLocker locker(&houseKeepingLock);
00203 houseKeepingWait.wakeAll();
00204 }
00205
00206 int period, maxhr, minhr;
00207 QString dbTag;
00208 bool initialRun = true;
00209
00210
00211 {
00212 QMutexLocker locker(&houseKeepingLock);
00213 houseKeepingWait.wait(locker.mutex(), 10 * 1000);
00214 }
00215
00216 RunStartupTasks();
00217
00218 QMutexLocker locker(&houseKeepingLock);
00219 while (houseKeepingRun)
00220 {
00221 locker.unlock();
00222
00223 LOG(VB_GENERAL, LOG_INFO, "Running housekeeping thread");
00224
00225
00226 if (isMaster)
00227 {
00228
00229 if (wantToRun("LogClean", 1, 0, 24))
00230 {
00231 LOG(VB_GENERAL, LOG_INFO, "Running LogClean");
00232 flushDBLogs();
00233 updateLastrun("LogClean");
00234 }
00235
00236
00237 if (gCoreContext->GetNumSetting("MythFillEnabled", 1))
00238 {
00239 if (fillDBThread && fillDBThread->isRunning())
00240 {
00241 LOG(VB_GENERAL, LOG_INFO,
00242 "mythfilldatabase still running, skipping checks.");
00243 }
00244 else
00245 {
00246 period = 1;
00247 minhr = gCoreContext->GetNumSetting("MythFillMinHour", -1);
00248 if (minhr == -1)
00249 {
00250 minhr = 0;
00251 maxhr = 24;
00252 }
00253 else
00254 {
00255 maxhr = gCoreContext->GetNumSetting("MythFillMaxHour", 24);
00256 }
00257
00258 bool grabberSupportsNextTime = false;
00259 MSqlQuery result(MSqlQuery::InitCon());
00260 if (result.isConnected())
00261 {
00262 result.prepare("SELECT COUNT(*) FROM videosource "
00263 "WHERE xmltvgrabber IN "
00264 "( 'datadirect', 'technovera',"
00265 " 'schedulesdirect1' );");
00266
00267 if ((result.exec()) &&
00268 (result.next()) &&
00269 (result.value(0).toInt() > 0))
00270 grabberSupportsNextTime = true;
00271 }
00272
00273 bool runMythFill = false;
00274 if (grabberSupportsNextTime &&
00275 gCoreContext->GetNumSetting("MythFillGrabberSuggestsTime", 1))
00276 {
00277 QDateTime nextRun = QDateTime::fromString(
00278 gCoreContext->GetSetting("MythFillSuggestedRunTime",
00279 "1970-01-01T00:00:00"), Qt::ISODate);
00280 QDateTime lastRun = getLastRun("MythFillDB");
00281 QDateTime now = QDateTime::currentDateTime();
00282
00283 if ((nextRun < now) &&
00284 (lastRun.secsTo(now) > (3 * 60 * 60)))
00285 runMythFill = true;
00286 }
00287 else if (wantToRun("MythFillDB", period, minhr, maxhr,
00288 initialRun))
00289 {
00290 runMythFill = true;
00291 }
00292
00293 if (runMythFill)
00294 {
00295 LOG(VB_GENERAL, LOG_INFO, "Running mythfilldatabase");
00296 StartMFD();
00297 updateLastrun("MythFillDB");
00298 }
00299 }
00300 }
00301
00302 if (wantToRun("DailyCleanup", 1, 0, 24)) {
00303 JobQueue::CleanupOldJobsInQueue();
00304 CleanupAllOldInUsePrograms();
00305 CleanupOrphanedLivetvChains();
00306 CleanupRecordedTables();
00307 CleanupProgramListings();
00308 updateLastrun("DailyCleanup");
00309 }
00310
00311 if ((gCoreContext->GetNumSetting("ThemeUpdateNofications", 1)) &&
00312 (wantToRun("ThemeChooserInfoCacheUpdate", 1, 0, 24, true)))
00313 {
00314 UpdateThemeChooserInfoCache();
00315 updateLastrun("ThemeChooserInfoCacheUpdate");
00316 }
00317
00318 #if CONFIG_BINDINGS_PYTHON
00319 if ((gCoreContext->GetNumSetting("DailyArtworkUpdates", 0)) &&
00320 (wantToRun("RecordedArtworkUpdate", 1, 0, 24, true)))
00321 {
00322 UpdateRecordedArtwork();
00323 updateLastrun("RecordedArtworkUpdate");
00324 }
00325 #endif
00326 }
00327
00328 dbTag = QString("JobQueueRecover-%1").arg(gCoreContext->GetHostName());
00329 if (wantToRun(dbTag, 1, 0, 24))
00330 {
00331 JobQueue::RecoverOldJobsInQueue();
00332 updateLastrun(dbTag);
00333 }
00334
00335 if (wantToRun("DBCleanup", 1, 0, 24))
00336 {
00337 gCoreContext->GetDBManager()->PurgeIdleConnections();
00338 }
00339
00340 initialRun = false;
00341
00342 locker.relock();
00343 if (houseKeepingRun)
00344 houseKeepingWait.wait(locker.mutex(), (300 + (random()%8)) * 1000);
00345 }
00346 }
00347
00348 void HouseKeeper::flushDBLogs()
00349 {
00350 int numdays = 14;
00351 uint64_t maxrows = 10000 * numdays;
00352
00353 MSqlQuery query(MSqlQuery::InitCon());
00354 if (query.isConnected())
00355 {
00356
00357 QDateTime days = QDateTime::currentDateTime();
00358 days = days.addDays(0 - (numdays / 2));
00359 QString sql = "DELETE FROM logging "
00360 " WHERE application NOT IN (:MYTHBACKEND, :MYTHFRONTEND) "
00361 " AND msgtime < :DAYS ;";
00362 query.prepare(sql);
00363 query.bindValue(":MYTHBACKEND", MYTH_APPNAME_MYTHBACKEND);
00364 query.bindValue(":MYTHFRONTEND", MYTH_APPNAME_MYTHFRONTEND);
00365 query.bindValue(":DAYS", days);
00366 LOG(VB_GENERAL, LOG_DEBUG,
00367 QString("Deleting helper application database log entries "
00368 "from before %1.") .arg(days.toString()));
00369 if (!query.exec())
00370 MythDB::DBError("Delete helper application log entries", query);
00371
00372
00373 days = QDateTime::currentDateTime();
00374 days = days.addDays(0 - numdays);
00375 sql = "DELETE FROM logging WHERE msgtime < :DAYS ;";
00376 query.prepare(sql);
00377 query.bindValue(":DAYS", days);
00378 LOG(VB_GENERAL, LOG_DEBUG,
00379 QString("Deleting database log entries from before %1.")
00380 .arg(days.toString()));
00381 if (!query.exec())
00382 MythDB::DBError("Delete old log entries", query);
00383
00384 sql = "SELECT COUNT(id) FROM logging;";
00385 query.prepare(sql);
00386 if (query.exec())
00387 {
00388 uint64_t totalrows = 0;
00389 while (query.next())
00390 {
00391 totalrows = query.value(0).toLongLong();
00392 LOG(VB_GENERAL, LOG_DEBUG,
00393 QString("Database has %1 log entries.").arg(totalrows));
00394 }
00395 if (totalrows > maxrows)
00396 {
00397 sql = "DELETE FROM logging ORDER BY msgtime LIMIT :ROWS;";
00398 query.prepare(sql);
00399 quint64 extrarows = totalrows - maxrows;
00400 query.bindValue(":ROWS", extrarows);
00401 LOG(VB_GENERAL, LOG_DEBUG,
00402 QString("Deleting oldest %1 database log entries.")
00403 .arg(extrarows));
00404 if (!query.exec())
00405 MythDB::DBError("Delete excess log entries", query);
00406 }
00407 }
00408 else
00409 MythDB::DBError("Query logging table size", query);
00410 }
00411 }
00412
00413 void HouseKeeper::RunMFD(void)
00414 {
00415 {
00416 QMutexLocker locker(&fillDBLock);
00417 fillDBStarted = true;
00418 fillDBWait.wakeAll();
00419 }
00420
00421 QString mfpath = gCoreContext->GetSetting("MythFillDatabasePath",
00422 "mythfilldatabase");
00423 QString mfarg = gCoreContext->GetSetting("MythFillDatabaseArgs", "");
00424
00425 if (mfpath == "mythfilldatabase")
00426 mfpath = GetInstallPrefix() + "/bin/mythfilldatabase";
00427
00428 QString command = QString("%1 %2 %3").arg(mfpath).arg(logPropagateArgs)
00429 .arg(mfarg);
00430
00431 {
00432 QMutexLocker locker(&fillDBLock);
00433 fillDBMythSystem = new MythSystem(command, kMSRunShell |
00434 kMSAutoCleanup);
00435 fillDBMythSystem->Run(0);
00436 fillDBWait.wakeAll();
00437 }
00438
00439 MythFillDatabaseThread::setTerminationEnabled(true);
00440
00441 uint result = fillDBMythSystem->Wait(0);
00442
00443 MythFillDatabaseThread::setTerminationEnabled(false);
00444
00445 {
00446 QMutexLocker locker(&fillDBLock);
00447 fillDBMythSystem->deleteLater();
00448 fillDBMythSystem = NULL;
00449 fillDBWait.wakeAll();
00450 }
00451
00452 if (result != GENERIC_EXIT_OK)
00453 {
00454 LOG(VB_GENERAL, LOG_ERR, QString("MythFillDatabase command '%1' failed")
00455 .arg(command));
00456 }
00457 }
00458
00459 void HouseKeeper::StartMFD(void)
00460 {
00461 if (fillDBThread)
00462 {
00463 KillMFD();
00464 delete fillDBThread;
00465 fillDBThread = NULL;
00466 fillDBStarted = false;
00467 }
00468
00469 fillDBThread = new MythFillDatabaseThread(this);
00470 fillDBThread->start();
00471
00472 QMutexLocker locker(&fillDBLock);
00473 while (!fillDBStarted)
00474 fillDBWait.wait(locker.mutex());
00475 }
00476
00477 void HouseKeeper::KillMFD(void)
00478 {
00479 if (!fillDBThread->isRunning())
00480 return;
00481
00482 QMutexLocker locker(&fillDBLock);
00483 if (fillDBMythSystem && fillDBThread->isRunning())
00484 {
00485 fillDBMythSystem->Term(false);
00486 fillDBWait.wait(locker.mutex(), 50);
00487 }
00488
00489 if (fillDBMythSystem && fillDBThread->isRunning())
00490 {
00491 fillDBMythSystem->Term(true);
00492 fillDBWait.wait(locker.mutex(), 50);
00493 }
00494
00495 if (fillDBThread->isRunning())
00496 {
00497 fillDBThread->terminate();
00498 usleep(5000);
00499 }
00500
00501 if (fillDBThread->isRunning())
00502 {
00503 locker.unlock();
00504 fillDBThread->wait();
00505 }
00506 }
00507
00508 void HouseKeeper::CleanupMyOldRecordings(void)
00509 {
00510 MSqlQuery query(MSqlQuery::InitCon());
00511
00512 query.prepare("DELETE FROM inuseprograms "
00513 "WHERE hostname = :HOSTNAME AND "
00514 "( recusage = 'recorder' OR recusage LIKE 'Unknown %' );");
00515 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
00516 if (!query.exec())
00517 MythDB::DBError("HouseKeeper::CleanupMyOldRecordings", query);
00518 }
00519
00520 void HouseKeeper::CleanupAllOldInUsePrograms(void)
00521 {
00522 QDateTime fourHoursAgo = QDateTime::currentDateTime().addSecs(-4 * 60 * 60);
00523 MSqlQuery query(MSqlQuery::InitCon());
00524
00525 query.prepare("DELETE FROM inuseprograms "
00526 "WHERE lastupdatetime < :FOURHOURSAGO ;");
00527 query.bindValue(":FOURHOURSAGO", fourHoursAgo);
00528 if (!query.exec())
00529 MythDB::DBError("HouseKeeper::CleanupAllOldInUsePrograms", query);
00530 }
00531
00532 void HouseKeeper::CleanupOrphanedLivetvChains(void)
00533 {
00534 QDateTime fourHoursAgo = QDateTime::currentDateTime().addSecs(-4 * 60 * 60);
00535 MSqlQuery query(MSqlQuery::InitCon());
00536 MSqlQuery deleteQuery(MSqlQuery::InitCon());
00537
00538
00539 query.prepare("SELECT DISTINCT chainid FROM tvchain "
00540 "WHERE endtime > :FOURHOURSAGO ;");
00541 query.bindValue(":FOURHOURSAGO", fourHoursAgo);
00542
00543 if (!query.exec() || !query.isActive())
00544 {
00545 MythDB::DBError("HouseKeeper Cleaning TVChain Table", query);
00546 return;
00547 }
00548
00549 QString msg, keepChains;
00550 while (query.next())
00551 if (keepChains.isEmpty())
00552 keepChains = "'" + query.value(0).toString() + "'";
00553 else
00554 keepChains += ", '" + query.value(0).toString() + "'";
00555
00556 if (keepChains.isEmpty())
00557 msg = "DELETE FROM tvchain WHERE endtime < now();";
00558 else
00559 {
00560 msg = QString("DELETE FROM tvchain "
00561 "WHERE chainid NOT IN ( %1 ) AND endtime < now();")
00562 .arg(keepChains);
00563 }
00564 deleteQuery.prepare(msg);
00565 if (!deleteQuery.exec())
00566 MythDB::DBError("HouseKeeper Cleaning TVChain Table", deleteQuery);
00567 }
00568
00569 void HouseKeeper::CleanupRecordedTables(void)
00570 {
00571 MSqlQuery query(MSqlQuery::InitCon());
00572 MSqlQuery deleteQuery(MSqlQuery::InitCon());
00573 int tableIndex = 0;
00574
00575
00576
00577 QString tables[][2] = {
00578 { "recordedprogram", "progstart" },
00579 { "recordedrating", "progstart" },
00580 { "recordedcredits", "progstart" },
00581 { "recordedmarkup", "starttime" },
00582 { "recordedseek", "starttime" },
00583 { "", "" } };
00584 QString table = tables[tableIndex][0];
00585 QString column = tables[tableIndex][1];
00586
00587
00588
00589
00590
00591 QString querystr;
00592 querystr = "CREATE TEMPORARY TABLE IF NOT EXISTS temprecordedcleanup ( "
00593 "chanid int(10) unsigned NOT NULL default '0', "
00594 "starttime datetime NOT NULL default '0000-00-00 00:00:00' "
00595 ");";
00596
00597 if (!query.exec(querystr))
00598 {
00599 MythDB::DBError("Housekeeper Creating Temporary Table", query);
00600 return;
00601 }
00602
00603 while (!table.isEmpty())
00604 {
00605 query.prepare(QString("TRUNCATE TABLE temprecordedcleanup;"));
00606 if (!query.exec() || !query.isActive())
00607 {
00608 MythDB::DBError("Housekeeper Truncating Temporary Table", query);
00609 return;
00610 }
00611
00612 query.prepare(QString("INSERT INTO temprecordedcleanup "
00613 "( chanid, starttime ) "
00614 "SELECT DISTINCT chanid, starttime "
00615 "FROM %1;")
00616 .arg(table));
00617
00618 if (!query.exec() || !query.isActive())
00619 {
00620 MythDB::DBError("HouseKeeper Cleaning Recorded Tables", query);
00621 return;
00622 }
00623
00624 query.prepare(QString("SELECT DISTINCT p.chanid, p.starttime "
00625 "FROM temprecordedcleanup p "
00626 "LEFT JOIN recorded r "
00627 "ON p.chanid = r.chanid "
00628 "AND p.starttime = r.%1 "
00629 "WHERE r.chanid IS NULL;").arg(column));
00630 if (!query.exec() || !query.isActive())
00631 {
00632 MythDB::DBError("HouseKeeper Cleaning Recorded Tables", query);
00633 return;
00634 }
00635
00636 deleteQuery.prepare(QString("DELETE FROM %1 "
00637 "WHERE chanid = :CHANID "
00638 "AND starttime = :STARTTIME;")
00639 .arg(table));
00640 while (query.next())
00641 {
00642 deleteQuery.bindValue(":CHANID", query.value(0).toString());
00643 deleteQuery.bindValue(":STARTTIME", query.value(1).toDateTime());
00644 if (!deleteQuery.exec())
00645 MythDB::DBError("HouseKeeper Cleaning Recorded Tables",
00646 deleteQuery);
00647 }
00648
00649 tableIndex++;
00650 table = tables[tableIndex][0];
00651 column = tables[tableIndex][1];
00652 }
00653
00654 if (!query.exec("DROP TABLE temprecordedcleanup;"))
00655 MythDB::DBError("Housekeeper Dropping Temporary Table", query);
00656
00657 }
00658
00659 void HouseKeeper::CleanupProgramListings(void)
00660 {
00661
00662 MSqlQuery query(MSqlQuery::InitCon());
00663 QString querystr;
00664
00665
00666 int offset = gCoreContext->GetNumSetting( "CleanOldRecorded", 10);
00667
00668 query.prepare("DELETE FROM oldprogram WHERE airdate < "
00669 "DATE_SUB(CURRENT_DATE, INTERVAL 320 DAY);");
00670 if (!query.exec())
00671 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
00672
00673 query.prepare("REPLACE INTO oldprogram (oldtitle,airdate) "
00674 "SELECT title,starttime FROM program "
00675 "WHERE starttime < NOW() AND manualid = 0 "
00676 "GROUP BY title;");
00677 if (!query.exec())
00678 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
00679
00680 query.prepare("DELETE FROM program WHERE starttime <= "
00681 "DATE_SUB(CURRENT_DATE, INTERVAL :OFFSET DAY);");
00682 query.bindValue(":OFFSET", offset);
00683 if (!query.exec())
00684 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
00685
00686 query.prepare("DELETE FROM programrating WHERE starttime <= "
00687 "DATE_SUB(CURRENT_DATE, INTERVAL :OFFSET DAY);");
00688 query.bindValue(":OFFSET", offset);
00689 if (!query.exec())
00690 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
00691
00692 query.prepare("DELETE FROM programgenres WHERE starttime <= "
00693 "DATE_SUB(CURRENT_DATE, INTERVAL :OFFSET DAY);");
00694 query.bindValue(":OFFSET", offset);
00695 if (!query.exec())
00696 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
00697
00698 query.prepare("DELETE FROM credits WHERE starttime <= "
00699 "DATE_SUB(CURRENT_DATE, INTERVAL :OFFSET DAY);");
00700 query.bindValue(":OFFSET", offset);
00701 if (!query.exec())
00702 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
00703
00704 query.prepare("DELETE FROM record WHERE (type = :SINGLE "
00705 "OR type = :OVERRIDE OR type = :DONTRECORD) "
00706 "AND enddate < CURDATE();");
00707 query.bindValue(":SINGLE", kSingleRecord);
00708 query.bindValue(":OVERRIDE", kOverrideRecord);
00709 query.bindValue(":DONTRECORD", kDontRecord);
00710 if (!query.exec())
00711 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
00712
00713 MSqlQuery findq(MSqlQuery::InitCon());
00714 findq.prepare("SELECT record.recordid FROM record "
00715 "LEFT JOIN oldfind ON oldfind.recordid = record.recordid "
00716 "WHERE type = :FINDONE AND oldfind.findid IS NOT NULL;");
00717 findq.bindValue(":FINDONE", kFindOneRecord);
00718
00719 if (findq.exec())
00720 {
00721 query.prepare("DELETE FROM record WHERE recordid = :RECORDID;");
00722 while (findq.next())
00723 {
00724 query.bindValue(":RECORDID", findq.value(0).toInt());
00725 if (!query.exec())
00726 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
00727 }
00728 }
00729 query.prepare("DELETE FROM oldfind WHERE findid < TO_DAYS(NOW()) - 14;");
00730 if (!query.exec())
00731 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
00732
00733 query.prepare("DELETE FROM oldrecorded WHERE "
00734 "recstatus <> :RECORDED AND duplicate = 0 AND "
00735 "endtime < DATE_SUB(CURRENT_DATE, INTERVAL :CLEAN DAY);");
00736 query.bindValue(":RECORDED", rsRecorded);
00737 query.bindValue(":CLEAN", offset);
00738 if (!query.exec())
00739 MythDB::DBError("HouseKeeper Cleaning Program Listings", query);
00740
00741 }
00742
00743 void HouseKeeper::UpdateThemeChooserInfoCache(void)
00744 {
00745 QString MythVersion = MYTH_SOURCE_PATH;
00746
00747
00748 if (MythVersion == "master")
00749 MythVersion = "trunk";
00750
00751 if (MythVersion != "trunk")
00752 {
00753 MythVersion = MYTH_BINARY_VERSION;
00754 MythVersion.replace(QRegExp("\\.[0-9]{8,}.*"), "");
00755 }
00756
00757 QString remoteThemesDir = GetConfDir();
00758 remoteThemesDir.append("/tmp/remotethemes");
00759
00760 QDir dir(remoteThemesDir);
00761 if (!dir.exists() && !dir.mkpath(remoteThemesDir))
00762 {
00763 LOG(VB_GENERAL, LOG_ERR,
00764 QString("HouseKeeper: Error creating %1"
00765 "directory for remote themes info cache.")
00766 .arg(remoteThemesDir));
00767 return;
00768 }
00769
00770 QString remoteThemesFile = remoteThemesDir;
00771 remoteThemesFile.append("/themes.zip");
00772
00773 QString url = QString("%1/%2/themes.zip")
00774 .arg(gCoreContext->GetSetting("ThemeRepositoryURL",
00775 "http://themes.mythtv.org/themes/repository")).arg(MythVersion);
00776
00777 bool result = GetMythDownloadManager()->download(url, remoteThemesFile);
00778
00779 if (!result)
00780 {
00781 LOG(VB_GENERAL, LOG_ERR,
00782 QString("HouseKeeper: Error downloading %1"
00783 "remote themes info package.").arg(url));
00784 return;
00785 }
00786
00787 if (!extractZIP(remoteThemesFile, remoteThemesDir))
00788 {
00789 LOG(VB_GENERAL, LOG_ERR,
00790 QString("HouseKeeper: Error extracting %1"
00791 "remote themes info package.").arg(remoteThemesFile));
00792 QFile::remove(remoteThemesFile);
00793 return;
00794 }
00795 }
00796
00797 void HouseKeeper::UpdateRecordedArtwork(void)
00798 {
00799 QString command = GetInstallPrefix() + "/bin/mythmetadatalookup";
00800 QStringList args;
00801 args << "--refresh-all-artwork";
00802 args << logPropagateArgs;
00803
00804 LOG(VB_GENERAL, LOG_INFO, QString("Performing Artwork Refresh: %1 %2")
00805 .arg(command).arg(args.join(" ")));
00806
00807 MythSystem artupd(command, args, kMSRunShell | kMSAutoCleanup);
00808
00809 artupd.Run();
00810 artupd.Wait();
00811
00812 LOG(VB_GENERAL, LOG_INFO, QString("Artwork Refresh Complete"));
00813 }
00814
00815 void HouseKeeper::RunStartupTasks(void)
00816 {
00817 if (isMaster)
00818 EITCache::ClearChannelLocks();
00819 }
00820
00821