|
MythTV
0.26-pre
|
00001 // POSIX headers 00002 #include <unistd.h> 00003 00004 // Std C headers 00005 #include <cstdlib> 00006 #include <ctime> 00007 00008 // C++ headers 00009 #include <fstream> 00010 using namespace std; 00011 00012 // Qt headers 00013 #include <QTextStream> 00014 #include <QDateTime> 00015 #include <QFile> 00016 #include <QList> 00017 #include <QMap> 00018 #include <QDir> 00019 00020 // libmyth headers 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 // libmythtv headers 00031 #include "videosource.h" // for is_grabber.. 00032 00033 // filldata headers 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 // DataDirect stuff 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 // User must pass "--do-channel-updates" for these updates 00114 if (chan_data.channel_updates) 00115 { 00116 DataDirectProcessor::UpdateChannelsUnsafe( 00117 source.id, chan_data.filter_new_channels); 00118 } 00119 // TODO delete any channels which no longer exist in listings source 00120 00121 if (update_icons) 00122 icon_data.UpdateSourceIcons(source.id); 00123 00124 // Unselect channels not in users lineup for DVB, HDTV 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)/*only sel*/); 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 // XMLTV stuff 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 // The one concession to grabber specific behaviour. 00402 // Will be removed when the grabber allows. 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 // XMLTV Docs don't recommend grabbing one day at a 00411 // time but the current MythTV code is heavily geared 00412 // that way so until it is re-written behave as 00413 // we always have done. 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 // Append additional arguments passed to mythfilldatabase 00421 // using --graboptions 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 // find all DataDirect duplicates, so we only data download once. 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 // We'll keep grabbing until it returns nothing 00721 // Max days currently supported is 21 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 // We need to check and see if the current date has changed 00745 // since we started in this loop. If it has, we need to adjust 00746 // the value of 'i' to compensate for this. 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, ""); // add a space between days 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 // Check to see if we already downloaded data for this date. 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 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1