00001
00002 #include <unistd.h>
00003
00004
00005 #include <cstdlib>
00006 #include <ctime>
00007
00008
00009 #include <fstream>
00010 using namespace std;
00011
00012
00013 #include <QTextStream>
00014 #include <QDateTime>
00015 #include <QFile>
00016 #include <QList>
00017 #include <QMap>
00018 #include <QDir>
00019
00020
00021 #include "exitcodes.h"
00022 #include "mythlogging.h"
00023 #include "mythdbcon.h"
00024 #include "compat.h"
00025 #include "mythmiscutil.h"
00026 #include "mythdirs.h"
00027 #include "mythdb.h"
00028 #include "mythsystem.h"
00029
00030
00031 #include "videosource.h"
00032
00033
00034 #include "filldata.h"
00035
00036 #define LOC QString("FillData: ")
00037 #define LOC_WARN QString("FillData, Warning: ")
00038 #define LOC_ERR QString("FillData, Error: ")
00039
00040 bool updateLastRunEnd(MSqlQuery &query)
00041 {
00042 QDateTime qdtNow = QDateTime::currentDateTime();
00043 query.prepare("UPDATE settings SET data = :ENDTIME "
00044 "WHERE value='mythfilldatabaseLastRunEnd'");
00045
00046 query.bindValue(":ENDTIME", qdtNow);
00047
00048 if (!query.exec())
00049 {
00050 MythDB::DBError("updateLastRunEnd", query);
00051 return false;
00052 }
00053 return true;
00054 }
00055
00056 bool updateLastRunStart(MSqlQuery &query)
00057 {
00058 QDateTime qdtNow = QDateTime::currentDateTime();
00059 query.prepare("UPDATE settings SET data = :STARTTIME "
00060 "WHERE value='mythfilldatabaseLastRunStart'");
00061
00062 query.bindValue(":STARTTIME", qdtNow);
00063
00064 if (!query.exec())
00065 {
00066 MythDB::DBError("updateLastRunStart", query);
00067 return false;
00068 }
00069 return true;
00070 }
00071
00072 bool updateLastRunStatus(MSqlQuery &query, QString &status)
00073 {
00074 query.prepare("UPDATE settings SET data = :STATUS "
00075 "WHERE value='mythfilldatabaseLastRunStatus'");
00076
00077 query.bindValue(":STATUS", status);
00078
00079 if (!query.exec())
00080 {
00081 MythDB::DBError("updateLastRunStatus", query);
00082 return false;
00083 }
00084 return true;
00085 }
00086
00087 void FillData::SetRefresh(int day, bool set)
00088 {
00089 if (kRefreshClear == day)
00090 {
00091 refresh_all = set;
00092 refresh_day.clear();
00093 }
00094 else if (kRefreshAll == day)
00095 {
00096 refresh_all = set;
00097 }
00098 else
00099 {
00100 refresh_day[(uint)day] = set;
00101 }
00102 }
00103
00104
00105 void FillData::DataDirectStationUpdate(Source source, bool update_icons)
00106 {
00107 DataDirectProcessor::UpdateStationViewTable(source.lineupid);
00108
00109 bool insert_channels = chan_data.insert_chan(source.id);
00110 int new_channels = DataDirectProcessor::UpdateChannelsSafe(
00111 source.id, insert_channels, chan_data.filter_new_channels);
00112
00113
00114 if (chan_data.channel_updates)
00115 {
00116 DataDirectProcessor::UpdateChannelsUnsafe(
00117 source.id, chan_data.filter_new_channels);
00118 }
00119
00120
00121 if (update_icons)
00122 icon_data.UpdateSourceIcons(source.id);
00123
00124
00125 if (!insert_channels && (new_channels > 0) &&
00126 is_grabber_labs(source.xmltvgrabber))
00127 {
00128 bool ok0 = (logged_in == source.userid);
00129 bool ok1 = (raw_lineup == source.id);
00130 if (!ok0)
00131 {
00132 LOG(VB_GENERAL, LOG_INFO,
00133 "Grabbing login cookies for listing update");
00134 ok0 = ddprocessor.GrabLoginCookiesAndLineups();
00135 }
00136 if (ok0 && !ok1)
00137 {
00138 LOG(VB_GENERAL, LOG_INFO, "Grabbing listing for listing update");
00139 ok1 = ddprocessor.GrabLineupForModify(source.lineupid);
00140 }
00141 if (ok1)
00142 {
00143 ddprocessor.UpdateListings(source.id);
00144 LOG(VB_GENERAL, LOG_INFO,
00145 QString("Removed %1 channel(s) from lineup.")
00146 .arg(new_channels));
00147 }
00148 }
00149 }
00150
00151 bool FillData::DataDirectUpdateChannels(Source source)
00152 {
00153 if (get_datadirect_provider(source.xmltvgrabber) >= 0)
00154 {
00155 ddprocessor.SetListingsProvider(
00156 get_datadirect_provider(source.xmltvgrabber));
00157 }
00158 else
00159 {
00160 LOG(VB_GENERAL, LOG_ERR, LOC +
00161 "We only support DataDirectUpdateChannels with "
00162 "TMS Labs and Schedules Direct.");
00163 return false;
00164 }
00165
00166 ddprocessor.SetUserID(source.userid);
00167 ddprocessor.SetPassword(source.password);
00168
00169 bool ok = true;
00170 if (!is_grabber_labs(source.xmltvgrabber))
00171 {
00172 ok = ddprocessor.GrabLineupsOnly();
00173 }
00174 else
00175 {
00176 ok = ddprocessor.GrabFullLineup(
00177 source.lineupid, true, chan_data.insert_chan(source.id));
00178 logged_in = source.userid;
00179 raw_lineup = source.id;
00180 }
00181
00182 if (ok)
00183 DataDirectStationUpdate(source, false);
00184
00185 return ok;
00186 }
00187
00188 bool FillData::GrabDDData(Source source, int poffset,
00189 QDate pdate, int ddSource)
00190 {
00191 if (source.dd_dups.empty())
00192 ddprocessor.SetCacheData(false);
00193 else
00194 {
00195 LOG(VB_GENERAL, LOG_INFO,
00196 QString("This DataDirect listings source is "
00197 "shared by %1 MythTV lineups")
00198 .arg(source.dd_dups.size()+1));
00199 if (source.id > source.dd_dups[0])
00200 {
00201 LOG(VB_GENERAL, LOG_NOTICE,
00202 "We should use cached data for this one");
00203 }
00204 else if (source.id < source.dd_dups[0])
00205 {
00206 LOG(VB_GENERAL, LOG_NOTICE,
00207 "We should keep data around after this one");
00208 }
00209 ddprocessor.SetCacheData(true);
00210 }
00211
00212 ddprocessor.SetListingsProvider(ddSource);
00213 ddprocessor.SetUserID(source.userid);
00214 ddprocessor.SetPassword(source.password);
00215
00216 bool needtoretrieve = true;
00217
00218 if (source.userid != lastdduserid)
00219 dddataretrieved = false;
00220
00221 if (dd_grab_all && dddataretrieved)
00222 needtoretrieve = false;
00223
00224 MSqlQuery query(MSqlQuery::DDCon());
00225 QString status = QObject::tr("currently running.");
00226
00227 updateLastRunStart(query);
00228
00229 if (needtoretrieve)
00230 {
00231 LOG(VB_GENERAL, LOG_INFO, "Retrieving datadirect data.");
00232 if (dd_grab_all)
00233 {
00234 LOG(VB_GENERAL, LOG_INFO, "Grabbing ALL available data.");
00235 if (!ddprocessor.GrabAllData())
00236 {
00237 LOG(VB_GENERAL, LOG_ERR, "Encountered error in grabbing data.");
00238 return false;
00239 }
00240 }
00241 else
00242 {
00243 QDateTime fromdatetime = QDateTime(pdate).toUTC().addDays(poffset);
00244 QDateTime todatetime = fromdatetime.addDays(1);
00245
00246 LOG(VB_GENERAL, LOG_INFO, QString("Grabbing data for %1 offset %2")
00247 .arg(pdate.toString())
00248 .arg(poffset));
00249 LOG(VB_GENERAL, LOG_INFO, QString("From %1 to %2 (UTC)")
00250 .arg(fromdatetime.toString())
00251 .arg(todatetime.toString()));
00252
00253 if (!ddprocessor.GrabData(fromdatetime, todatetime))
00254 {
00255 LOG(VB_GENERAL, LOG_ERR, "Encountered error in grabbing data.");
00256 return false;
00257 }
00258 }
00259
00260 dddataretrieved = true;
00261 lastdduserid = source.userid;
00262 }
00263 else
00264 {
00265 LOG(VB_GENERAL, LOG_INFO,
00266 "Using existing grabbed data in temp tables.");
00267 }
00268
00269 LOG(VB_GENERAL, LOG_INFO,
00270 QString("Grab complete. Actual data from %1 to %2 (UTC)")
00271 .arg(ddprocessor.GetDDProgramsStartAt().toString())
00272 .arg(ddprocessor.GetDDProgramsEndAt().toString()));
00273
00274 updateLastRunEnd(query);
00275
00276 LOG(VB_GENERAL, LOG_INFO, "Main temp tables populated.");
00277 if (!channel_update_run)
00278 {
00279 LOG(VB_GENERAL, LOG_INFO, "Updating MythTV channels.");
00280 DataDirectStationUpdate(source);
00281 LOG(VB_GENERAL, LOG_INFO, "Channels updated.");
00282 channel_update_run = true;
00283 }
00284
00285 #if 0
00286 LOG(VB_GENERAL, LOG_INFO, "Creating program view table...");
00287 #endif
00288 DataDirectProcessor::UpdateProgramViewTable(source.id);
00289 #if 0
00290 LOG(VB_GENERAL, LOG_INFO, "Finished creating program view table...");
00291 #endif
00292
00293 query.prepare("SELECT count(*) from dd_v_program;");
00294 if (query.exec() && query.next())
00295 {
00296 if (query.value(0).toInt() < 1)
00297 {
00298 LOG(VB_GENERAL, LOG_INFO, "Did not find any new program data.");
00299 return false;
00300 }
00301 }
00302 else
00303 {
00304 LOG(VB_GENERAL, LOG_ERR, "Failed testing program view table.");
00305 return false;
00306 }
00307
00308 LOG(VB_GENERAL, LOG_INFO, "Clearing data for source.");
00309 QDateTime fromlocaldt = ddprocessor.GetDDProgramsStartAt(true);
00310 QDateTime tolocaldt = ddprocessor.GetDDProgramsEndAt(true);
00311
00312 LOG(VB_GENERAL, LOG_INFO, QString("Clearing from %1 to %2 (localtime)")
00313 .arg(fromlocaldt.toString())
00314 .arg(tolocaldt.toString()));
00315 ProgramData::ClearDataBySource(source.id, fromlocaldt, tolocaldt, true);
00316 LOG(VB_GENERAL, LOG_INFO, "Data for source cleared.");
00317
00318 LOG(VB_GENERAL, LOG_INFO, "Updating programs.");
00319 DataDirectProcessor::DataDirectProgramUpdate();
00320 LOG(VB_GENERAL, LOG_INFO, "Program table update complete.");
00321
00322 return true;
00323 }
00324
00325
00326 bool FillData::GrabDataFromFile(int id, QString &filename)
00327 {
00328 QList<ChanInfo> chanlist;
00329 QMap<QString, QList<ProgInfo> > proglist;
00330
00331 if (!xmltv_parser.parseFile(filename, &chanlist, &proglist))
00332 return false;
00333
00334 chan_data.handleChannels(id, &chanlist);
00335 icon_data.UpdateSourceIcons(id);
00336 if (proglist.count() == 0)
00337 {
00338 LOG(VB_GENERAL, LOG_INFO, "No programs found in data.");
00339 endofdata = true;
00340 }
00341 else
00342 {
00343 prog_data.HandlePrograms(id, proglist);
00344 }
00345 return true;
00346 }
00347
00348 bool FillData::GrabData(Source source, int offset, QDate *qCurrentDate)
00349 {
00350 QString xmltv_grabber = source.xmltvgrabber;
00351
00352 int dd_provider = get_datadirect_provider(xmltv_grabber);
00353 if (dd_provider >= 0)
00354 {
00355 if (!GrabDDData(source, offset, *qCurrentDate, dd_provider))
00356 {
00357 QStringList errors = ddprocessor.GetFatalErrors();
00358 for (int i = 0; i < errors.size(); i++)
00359 fatalErrors.push_back(errors[i]);
00360 return false;
00361 }
00362 return true;
00363 }
00364
00365 const QString templatename = "/tmp/mythXXXXXX";
00366 const QString tempfilename = createTempFile(templatename);
00367 if (templatename == tempfilename)
00368 {
00369 fatalErrors.push_back("Failed to create temporary file.");
00370 return false;
00371 }
00372
00373 QString filename = QString(tempfilename);
00374
00375 QString home = QDir::homePath();
00376
00377 QString configfile;
00378
00379 MSqlQuery query1(MSqlQuery::InitCon());
00380 query1.prepare("SELECT configpath FROM videosource"
00381 " WHERE sourceid = :ID AND configpath IS NOT NULL");
00382 query1.bindValue(":ID", source.id);
00383 if (!query1.exec())
00384 {
00385 MythDB::DBError("FillData::grabData", query1);
00386 return false;
00387 }
00388
00389 if (query1.next())
00390 configfile = query1.value(0).toString();
00391 else
00392 configfile = QString("%1/%2.xmltv").arg(GetConfDir())
00393 .arg(source.name);
00394
00395 LOG(VB_GENERAL, LOG_INFO,
00396 QString("XMLTV config file is: %1").arg(configfile));
00397
00398 QString command = QString("nice %1 --config-file '%2' --output %3")
00399 .arg(xmltv_grabber).arg(configfile).arg(filename);
00400
00401
00402
00403 if (xmltv_grabber == "tv_grab_jp")
00404 {
00405 command += QString(" --enable-readstr");
00406 xmltv_parser.isJapan = true;
00407 }
00408 else if (source.xmltvgrabber_prefmethod != "allatonce")
00409 {
00410
00411
00412
00413
00414 command += QString(" --days 1 --offset %1").arg(offset);
00415 }
00416
00417 if (!VERBOSE_LEVEL_CHECK(VB_XMLTV, LOG_ANY))
00418 command += " --quiet";
00419
00420
00421
00422 if (!graboptions.isEmpty())
00423 {
00424 command += graboptions;
00425 LOG(VB_XMLTV, LOG_INFO,
00426 QString("Using graboptions: %1").arg(graboptions));
00427 }
00428
00429 MSqlQuery query(MSqlQuery::InitCon());
00430 QString status = QObject::tr("currently running.");
00431
00432 updateLastRunStart(query);
00433 updateLastRunStatus(query, status);
00434
00435 LOG(VB_XMLTV, LOG_INFO, QString("Grabber Command: %1").arg(command));
00436
00437 LOG(VB_XMLTV, LOG_INFO,
00438 "----------------- Start of XMLTV output -----------------");
00439
00440 unsigned int systemcall_status;
00441
00442 systemcall_status = myth_system(command, kMSRunShell);
00443 bool succeeded = (systemcall_status == GENERIC_EXIT_OK);
00444
00445 LOG(VB_XMLTV, LOG_INFO,
00446 "------------------ End of XMLTV output ------------------");
00447
00448 updateLastRunEnd(query);
00449
00450 status = QObject::tr("Successful.");
00451
00452 if (!succeeded)
00453 {
00454 if (systemcall_status == GENERIC_EXIT_KILLED)
00455 {
00456 interrupted = true;
00457 status =
00458 QString(QObject::tr("FAILED: xmltv ran but was interrupted."));
00459 }
00460 else
00461 {
00462 status =
00463 QString(QObject::tr("FAILED: xmltv returned error code %1."))
00464 .arg(systemcall_status);
00465 LOG(VB_GENERAL, LOG_ERR, LOC +
00466 QString("xmltv returned error code %1")
00467 .arg(systemcall_status));
00468 }
00469 }
00470
00471 updateLastRunStatus(query, status);
00472
00473 succeeded &= GrabDataFromFile(source.id, filename);
00474
00475 QFile thefile(filename);
00476 thefile.remove();
00477
00478 return succeeded;
00479 }
00480
00481 bool FillData::GrabDataFromDDFile(
00482 int id, int offset, const QString &filename,
00483 const QString &lineupid, QDate *qCurrentDate)
00484 {
00485 QDate *currentd = qCurrentDate;
00486 QDate qcd = QDate::currentDate();
00487 if (!currentd)
00488 currentd = &qcd;
00489
00490 ddprocessor.SetInputFile(filename);
00491 Source s;
00492 s.id = id;
00493 s.xmltvgrabber = "datadirect";
00494 s.userid = "fromfile";
00495 s.password = "fromfile";
00496 s.lineupid = lineupid;
00497
00498 return GrabData(s, offset, currentd);
00499 }
00500
00501
00507 bool FillData::Run(SourceList &sourcelist)
00508 {
00509 SourceList::iterator it;
00510 SourceList::iterator it2;
00511
00512 QString status, querystr;
00513 MSqlQuery query(MSqlQuery::InitCon());
00514 QDateTime GuideDataBefore, GuideDataAfter;
00515 int failures = 0;
00516 int externally_handled = 0;
00517 int total_sources = sourcelist.size();
00518 int source_channels = 0;
00519
00520 QString sidStr = QString("Updating source #%1 (%2) with grabber %3");
00521
00522 need_post_grab_proc = false;
00523 int nonewdata = 0;
00524 bool has_dd_source = false;
00525
00526
00527 for (it = sourcelist.begin(); it != sourcelist.end(); ++it)
00528 {
00529 if (!is_grabber_datadirect((*it).xmltvgrabber))
00530 continue;
00531
00532 has_dd_source = true;
00533 for (it2 = sourcelist.begin(); it2 != sourcelist.end(); ++it2)
00534 {
00535 if (((*it).id != (*it2).id) &&
00536 ((*it).xmltvgrabber == (*it2).xmltvgrabber) &&
00537 ((*it).userid == (*it2).userid) &&
00538 ((*it).password == (*it2).password))
00539 {
00540 (*it).dd_dups.push_back((*it2).id);
00541 }
00542 }
00543 }
00544 if (has_dd_source)
00545 ddprocessor.CreateTempDirectory();
00546
00547 for (it = sourcelist.begin(); it != sourcelist.end(); ++it)
00548 {
00549 if (!fatalErrors.empty())
00550 break;
00551
00552 query.prepare("SELECT MAX(endtime) FROM program p LEFT JOIN channel c "
00553 "ON p.chanid=c.chanid WHERE c.sourceid= :SRCID "
00554 "AND manualid = 0 AND c.xmltvid != '';");
00555 query.bindValue(":SRCID", (*it).id);
00556
00557 if (query.exec() && query.next())
00558 {
00559 if (!query.isNull(0))
00560 GuideDataBefore =
00561 QDateTime::fromString(query.value(0).toString(),
00562 Qt::ISODate);
00563 }
00564
00565 channel_update_run = false;
00566 endofdata = false;
00567
00568 QString xmltv_grabber = (*it).xmltvgrabber;
00569
00570 if (xmltv_grabber == "eitonly")
00571 {
00572 LOG(VB_GENERAL, LOG_INFO,
00573 QString("Source %1 configured to use only the "
00574 "broadcasted guide data. Skipping.") .arg((*it).id));
00575
00576 externally_handled++;
00577 updateLastRunStart(query);
00578 updateLastRunEnd(query);
00579 continue;
00580 }
00581 else if (xmltv_grabber.trimmed().isEmpty() ||
00582 xmltv_grabber == "/bin/true" ||
00583 xmltv_grabber == "none")
00584 {
00585 LOG(VB_GENERAL, LOG_INFO,
00586 QString("Source %1 configured with no grabber. Nothing to do.")
00587 .arg((*it).id));
00588
00589 externally_handled++;
00590 updateLastRunStart(query);
00591 updateLastRunEnd(query);
00592 continue;
00593 }
00594
00595 LOG(VB_GENERAL, LOG_INFO, sidStr.arg((*it).id)
00596 .arg((*it).name)
00597 .arg(xmltv_grabber));
00598
00599 query.prepare(
00600 "SELECT COUNT(chanid) FROM channel WHERE sourceid = "
00601 ":SRCID AND xmltvid != ''");
00602 query.bindValue(":SRCID", (*it).id);
00603
00604 if (query.exec() && query.next())
00605 {
00606 source_channels = query.value(0).toInt();
00607 if (source_channels > 0)
00608 {
00609 LOG(VB_GENERAL, LOG_INFO,
00610 QString("Found %1 channels for source %2 which use grabber")
00611 .arg(source_channels).arg((*it).id));
00612 }
00613 else
00614 {
00615 LOG(VB_GENERAL, LOG_INFO,
00616 QString("No channels are configured to use grabber."));
00617 }
00618 }
00619 else
00620 {
00621 source_channels = 0;
00622 LOG(VB_GENERAL, LOG_INFO,
00623 QString("Can't get a channel count for source id %1")
00624 .arg((*it).id));
00625 }
00626
00627 bool hasprefmethod = false;
00628
00629 if (is_grabber_external(xmltv_grabber))
00630 {
00631 uint flags = kMSRunShell | kMSStdOut | kMSBuffered;
00632 MythSystem grabber_capabilities_proc(xmltv_grabber,
00633 QStringList("--capabilities"),
00634 flags);
00635 grabber_capabilities_proc.Run(25);
00636 if (grabber_capabilities_proc.Wait() != GENERIC_EXIT_OK)
00637 LOG(VB_GENERAL, LOG_ERR,
00638 QString("%1 --capabilities failed or we timed out waiting."
00639 " You may need to upgrade your xmltv grabber")
00640 .arg(xmltv_grabber));
00641 else
00642 {
00643 QByteArray result = grabber_capabilities_proc.ReadAll();
00644 QTextStream ostream(result);
00645 QString capabilities;
00646 while (!ostream.atEnd())
00647 {
00648 QString capability
00649 = ostream.readLine().simplified();
00650
00651 if (capability.isEmpty())
00652 continue;
00653
00654 capabilities += capability + ' ';
00655
00656 if (capability == "baseline")
00657 (*it).xmltvgrabber_baseline = true;
00658
00659 if (capability == "manualconfig")
00660 (*it).xmltvgrabber_manualconfig = true;
00661
00662 if (capability == "cache")
00663 (*it).xmltvgrabber_cache = true;
00664
00665 if (capability == "preferredmethod")
00666 hasprefmethod = true;
00667 }
00668 LOG(VB_GENERAL, LOG_INFO,
00669 QString("Grabber has capabilities: %1") .arg(capabilities));
00670 }
00671 }
00672
00673 if (hasprefmethod)
00674 {
00675 uint flags = kMSRunShell | kMSStdOut | kMSBuffered;
00676 MythSystem grabber_method_proc(xmltv_grabber,
00677 QStringList("--preferredmethod"),
00678 flags);
00679 grabber_method_proc.Run(15);
00680 if (grabber_method_proc.Wait() != GENERIC_EXIT_OK)
00681 LOG(VB_GENERAL, LOG_ERR,
00682 QString("%1 --preferredmethod failed or we timed out "
00683 "waiting. You may need to upgrade your xmltv "
00684 "grabber").arg(xmltv_grabber));
00685 else
00686 {
00687 QTextStream ostream(grabber_method_proc.ReadAll());
00688 (*it).xmltvgrabber_prefmethod =
00689 ostream.readLine().simplified();
00690
00691 LOG(VB_GENERAL, LOG_INFO, QString("Grabber prefers method: %1")
00692 .arg((*it).xmltvgrabber_prefmethod));
00693 }
00694 }
00695
00696 need_post_grab_proc |= !is_grabber_datadirect(xmltv_grabber);
00697
00698 if (is_grabber_datadirect(xmltv_grabber) && dd_grab_all)
00699 {
00700 if (only_update_channels)
00701 DataDirectUpdateChannels(*it);
00702 else
00703 {
00704 QDate qCurrentDate = QDate::currentDate();
00705 if (!GrabData(*it, 0, &qCurrentDate))
00706 ++failures;
00707 }
00708 }
00709 else if ((*it).xmltvgrabber_prefmethod == "allatonce")
00710 {
00711 if (!GrabData(*it, 0))
00712 ++failures;
00713 }
00714 else if ((*it).xmltvgrabber_baseline ||
00715 is_grabber_datadirect(xmltv_grabber))
00716 {
00717
00718 QDate qCurrentDate = QDate::currentDate();
00719
00720
00721
00722 int grabdays = (is_grabber_datadirect(xmltv_grabber)) ?
00723 14 : REFRESH_MAX;
00724
00725 grabdays = (maxDays > 0) ? maxDays : grabdays;
00726 grabdays = (only_update_channels) ? 1 : grabdays;
00727
00728 vector<bool> refresh_request;
00729 refresh_request.resize(grabdays, refresh_all);
00730 for (int i = 0; i < refresh_day.size(); i++)
00731 refresh_request[i] = refresh_day[i];
00732
00733 if (is_grabber_datadirect(xmltv_grabber) && only_update_channels)
00734 {
00735 DataDirectUpdateChannels(*it);
00736 grabdays = 0;
00737 }
00738
00739 for (int i = 0; i < grabdays; i++)
00740 {
00741 if (!fatalErrors.empty())
00742 break;
00743
00744
00745
00746
00747 if (QDate::currentDate() != qCurrentDate)
00748 {
00749 QDate newDate = QDate::currentDate();
00750 i += (newDate.daysTo(qCurrentDate));
00751 if (i < 0)
00752 i = 0;
00753 qCurrentDate = newDate;
00754 }
00755
00756 QString prevDate(qCurrentDate.addDays(i-1).toString());
00757 QString currDate(qCurrentDate.addDays(i).toString());
00758
00759 LOG(VB_GENERAL, LOG_INFO, "");
00760 LOG(VB_GENERAL, LOG_INFO, "Checking day @ " +
00761 QString("offset %1, date: %2").arg(i).arg(currDate));
00762
00763 bool download_needed = false;
00764
00765 if (refresh_request[i])
00766 {
00767 if ( i == 1 )
00768 {
00769 LOG(VB_GENERAL, LOG_INFO,
00770 "Data Refresh always needed for tomorrow");
00771 }
00772 else
00773 {
00774 LOG(VB_GENERAL, LOG_INFO,
00775 "Data Refresh needed because of user request");
00776 }
00777 download_needed = true;
00778 }
00779 else
00780 {
00781
00782
00783 querystr = "SELECT c.chanid, COUNT(p.starttime) "
00784 "FROM channel c "
00785 "LEFT JOIN program p ON c.chanid = p.chanid "
00786 " AND starttime >= "
00787 "DATE_ADD(DATE_ADD(CURRENT_DATE(), "
00788 "INTERVAL '%1' DAY), INTERVAL '20' HOUR) "
00789 " AND starttime < DATE_ADD(CURRENT_DATE(), "
00790 "INTERVAL '%2' DAY) "
00791 "WHERE c.sourceid = %3 AND c.xmltvid != '' "
00792 "GROUP BY c.chanid;";
00793
00794 if (query.exec(querystr.arg(i-1).arg(i).arg((*it).id)) &&
00795 query.isActive())
00796 {
00797 int prevChanCount = 0;
00798 int currentChanCount = 0;
00799 int previousDayCount = 0;
00800 int currentDayCount = 0;
00801
00802 LOG(VB_CHANNEL, LOG_INFO,
00803 QString("Checking program counts for day %1")
00804 .arg(i-1));
00805
00806 while (query.next())
00807 {
00808 if (query.value(1).toInt() > 0)
00809 prevChanCount++;
00810 previousDayCount += query.value(1).toInt();
00811
00812 LOG(VB_CHANNEL, LOG_INFO,
00813 QString(" chanid %1 -> %2 programs")
00814 .arg(query.value(0).toString())
00815 .arg(query.value(1).toInt()));
00816 }
00817
00818 if (query.exec(querystr.arg(i).arg(i+1).arg((*it).id))
00819 && query.isActive())
00820 {
00821 LOG(VB_CHANNEL, LOG_INFO,
00822 QString("Checking program counts for day %1")
00823 .arg(i));
00824 while (query.next())
00825 {
00826 if (query.value(1).toInt() > 0)
00827 currentChanCount++;
00828 currentDayCount += query.value(1).toInt();
00829
00830 LOG(VB_CHANNEL, LOG_INFO,
00831 QString(" chanid %1 -> %2 programs")
00832 .arg(query.value(0).toString())
00833 .arg(query.value(1).toInt()));
00834 }
00835 }
00836 else
00837 {
00838 LOG(VB_GENERAL, LOG_INFO,
00839 QString("Data Refresh because we are unable to "
00840 "query the data for day %1 to "
00841 "determine if we have enough").arg(i));
00842 download_needed = true;
00843 }
00844
00845 if (currentChanCount < (prevChanCount * 0.90))
00846 {
00847 LOG(VB_GENERAL, LOG_INFO,
00848 QString("Data refresh needed because only %1 "
00849 "out of %2 channels have at least one "
00850 "program listed for day @ offset %3 "
00851 "from 8PM - midnight. Previous day "
00852 "had %4 channels with data in that "
00853 "time period.")
00854 .arg(currentChanCount).arg(source_channels)
00855 .arg(i).arg(prevChanCount));
00856 download_needed = true;
00857 }
00858 else if (currentDayCount == 0)
00859 {
00860 LOG(VB_GENERAL, LOG_INFO,
00861 QString("Data refresh needed because no data "
00862 "exists for day @ offset %1 from 8PM - "
00863 "midnight.").arg(i));
00864 download_needed = true;
00865 }
00866 else if (previousDayCount == 0)
00867 {
00868 LOG(VB_GENERAL, LOG_INFO,
00869 QString("Data refresh needed because no data "
00870 "exists for day @ offset %1 from 8PM - "
00871 "midnight. Unable to calculate how "
00872 "much we should have for the current "
00873 "day so a refresh is being forced.")
00874 .arg(i-1));
00875 download_needed = true;
00876 }
00877 else if (currentDayCount < (currentChanCount * 3))
00878 {
00879 LOG(VB_GENERAL, LOG_INFO,
00880 QString("Data Refresh needed because offset "
00881 "day %1 has less than 3 programs "
00882 "per channel for the 8PM - midnight "
00883 "time window for channels that "
00884 "normally have data. "
00885 "We want at least %2 programs, but "
00886 "only found %3")
00887 .arg(i).arg(currentChanCount * 3)
00888 .arg(currentDayCount));
00889 download_needed = true;
00890 }
00891 else if (currentDayCount < (previousDayCount / 2))
00892 {
00893 LOG(VB_GENERAL, LOG_INFO,
00894 QString("Data Refresh needed because offset "
00895 "day %1 has less than half the number "
00896 "of programs as the previous day for "
00897 "the 8PM - midnight time window. "
00898 "We want at least %2 programs, but "
00899 "only found %3").arg(i)
00900 .arg(previousDayCount / 2)
00901 .arg(currentDayCount));
00902 download_needed = true;
00903 }
00904 }
00905 else
00906 {
00907 LOG(VB_GENERAL, LOG_INFO,
00908 QString("Data Refresh needed because we are unable "
00909 "to query the data for day @ offset %1 to "
00910 "determine how much we should have for "
00911 "offset day %2.").arg(i-1).arg(i));
00912 download_needed = true;
00913 }
00914 }
00915
00916 if (download_needed)
00917 {
00918 LOG(VB_GENERAL, LOG_NOTICE,
00919 QString("Refreshing data for ") + currDate);
00920 if (!GrabData(*it, i, &qCurrentDate))
00921 {
00922 ++failures;
00923 if (!fatalErrors.empty() || interrupted)
00924 {
00925 break;
00926 }
00927 }
00928
00929 if (endofdata)
00930 {
00931 LOG(VB_GENERAL, LOG_INFO,
00932 "Grabber is no longer returning program data, "
00933 "finishing");
00934 break;
00935 }
00936 }
00937 else
00938 {
00939 LOG(VB_GENERAL, LOG_NOTICE,
00940 QString("Data is already present for ") + currDate +
00941 ", skipping");
00942 }
00943 }
00944 if (!fatalErrors.empty())
00945 break;
00946 }
00947 else
00948 {
00949 LOG(VB_GENERAL, LOG_ERR,
00950 QString("Grabbing XMLTV data using ") + xmltv_grabber +
00951 " is not supported. You may need to upgrade to"
00952 " the latest version of XMLTV.");
00953 }
00954
00955 if (interrupted)
00956 {
00957 break;
00958 }
00959
00960 query.prepare("SELECT MAX(endtime) FROM program p LEFT JOIN channel c "
00961 "ON p.chanid=c.chanid WHERE c.sourceid= :SRCID "
00962 "AND manualid = 0 AND c.xmltvid != '';");
00963 query.bindValue(":SRCID", (*it).id);
00964
00965 if (query.exec() && query.next())
00966 {
00967 if (!query.isNull(0))
00968 GuideDataAfter = QDateTime::fromString(
00969 query.value(0).toString(), Qt::ISODate);
00970 }
00971
00972 if (GuideDataAfter == GuideDataBefore)
00973 {
00974 nonewdata++;
00975 }
00976 }
00977
00978 if (!fatalErrors.empty())
00979 {
00980 for (int i = 0; i < fatalErrors.size(); i++)
00981 {
00982 LOG(VB_GENERAL, LOG_CRIT, LOC + "Encountered Fatal Error: " +
00983 fatalErrors[i]);
00984 }
00985 return false;
00986 }
00987
00988 if (only_update_channels && !need_post_grab_proc)
00989 return true;
00990
00991 if (failures == 0)
00992 {
00993 if (nonewdata > 0 &&
00994 (total_sources != externally_handled))
00995 status = QString(QObject::tr(
00996 "mythfilldatabase ran, but did not insert "
00997 "any new data into the Guide for %1 of %2 sources. "
00998 "This can indicate a potential grabber failure."))
00999 .arg(nonewdata)
01000 .arg(total_sources);
01001 else
01002 status = QObject::tr("Successful.");
01003
01004 updateLastRunStatus(query, status);
01005 }
01006
01007 return (failures == 0);
01008 }
01009
01010 ChanInfo *FillData::xawtvChannel(QString &id, QString &channel, QString &fine)
01011 {
01012 ChanInfo *chaninfo = new ChanInfo;
01013 chaninfo->xmltvid = id;
01014 chaninfo->name = id;
01015 chaninfo->callsign = id;
01016 if (chan_data.channel_preset)
01017 chaninfo->chanstr = id;
01018 else
01019 chaninfo->chanstr = channel;
01020 chaninfo->finetune = fine;
01021 chaninfo->freqid = channel;
01022 chaninfo->tvformat = "Default";
01023
01024 return chaninfo;
01025 }
01026
01027 void FillData::readXawtvChannels(int id, QString xawrcfile)
01028 {
01029 QByteArray tmp = xawrcfile.toAscii();
01030 fstream fin(tmp.constData(), ios::in);
01031
01032 if (!fin.is_open())
01033 return;
01034
01035 QList<ChanInfo> chanlist;
01036
01037 QString xawid;
01038 QString channel;
01039 QString fine;
01040
01041 string strLine;
01042 int nSplitPoint = 0;
01043
01044 while(!fin.eof())
01045 {
01046 getline(fin,strLine);
01047
01048 if ((strLine[0] != '#') && (!strLine.empty()))
01049 {
01050 if (strLine[0] == '[')
01051 {
01052 if ((nSplitPoint = strLine.find(']')) > 1)
01053 {
01054 if (!xawid.isEmpty() && !channel.isEmpty())
01055 {
01056 ChanInfo *chinfo = xawtvChannel(xawid, channel, fine);
01057 chanlist.push_back(*chinfo);
01058 delete chinfo;
01059 }
01060 xawid = strLine.substr(1, nSplitPoint - 1).c_str();
01061 channel.clear();
01062 fine.clear();
01063 }
01064 }
01065 else if ((nSplitPoint = strLine.find('=') + 1) > 0)
01066 {
01067 while (strLine.substr(nSplitPoint,1) == " ")
01068 { ++nSplitPoint; }
01069
01070 if (!strncmp(strLine.c_str(), "channel", 7))
01071 {
01072 channel = strLine.substr(nSplitPoint,
01073 strLine.size()).c_str();
01074 }
01075 else if (!strncmp(strLine.c_str(), "fine", 4))
01076 {
01077 fine = strLine.substr(nSplitPoint, strLine.size()).c_str();
01078 }
01079 }
01080 }
01081 }
01082
01083 if (!xawid.isEmpty() && !channel.isEmpty())
01084 {
01085 ChanInfo *chinfo = xawtvChannel(xawid, channel, fine);
01086 chanlist.push_back(*chinfo);
01087 delete chinfo;
01088 }
01089
01090 chan_data.handleChannels(id, &chanlist);
01091 icon_data.UpdateSourceIcons(id);
01092 }
01093
01094