MythTV  0.26-pre
filldata.cpp
Go to the documentation of this file.
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: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends