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