00001
00007 #include <qdeepcopy.h>
00008 #include <qdatetime.h>
00009 #include <qhttp.h>
00010
00011 #include "dbox2channel.h"
00012 #include "dbox2epg.h"
00013 #include "mythcontext.h"
00014 #include "tv_rec.h"
00015
00016 #define DEBUG_DBOX2EPG
00017
00018
00019
00020 #define LOC QString("DBox2EPG(%1): ").arg(m_cardid)
00021 #define LOC_WARN QString("DBox2EPG(%1) Warning: ").arg(m_cardid)
00022 #define LOC_ERR QString("DBox2EPG(%1) Error: ").arg(m_cardid)
00023
00024 DBox2EPG::DBox2EPG()
00025 : http(new QHttp()),
00026 m_dbox2options(NULL),
00027 m_dbox2channel(NULL),
00028 m_cardid(-1),
00029 m_channelCount(0),
00030 m_channelIndex(0),
00031 m_isRunning(true),
00032 m_inProgress(false),
00033 m_pendingRequest(false),
00034 m_requestedChannel(""),
00035 m_currentEPGRequestChannel(""),
00036 m_currentEPGRequestID(-1)
00037 {
00038 connect(http, SIGNAL(requestFinished (int,bool)),
00039 this, SLOT( httpRequestFinished(int,bool)));
00040 }
00041
00042 DBox2EPG::~DBox2EPG()
00043 {
00044 TeardownAll();
00045 }
00046
00050 void DBox2EPG::deleteLater(void)
00051 {
00052 disconnect();
00053 TeardownAll();
00054 QObject::deleteLater();
00055 }
00056
00057 void DBox2EPG::TeardownAll(void)
00058 {
00059 if (http)
00060 {
00061
00062 http->abort();
00063
00064 disconnect(http, SIGNAL(requestFinished (int,bool)),
00065 this, SLOT( httpRequestFinished(int,bool)));
00066
00067 http->deleteLater();
00068 }
00069 }
00070
00071 void DBox2EPG::Init(DBox2DBOptions* dbox2_options, int cardid,
00072 DBox2Channel* channel)
00073 {
00074 VERBOSE(VB_EIT, LOC + "Init run");
00075
00076 m_dbox2options = dbox2_options;
00077 m_dbox2channel = channel;
00078 m_cardid = cardid;
00079
00080 http->setHost(m_dbox2options->host, m_dbox2options->httpport);
00081
00082 start();
00083 }
00084
00085 void DBox2EPG::Shutdown()
00086 {
00087 m_isRunning = false;
00088 }
00089
00090 void DBox2EPG::run()
00091 {
00092 VERBOSE(VB_EIT, LOC + "Starting Thread....");
00093 long waitTime = 15 * 1000 * 1000;
00094
00095
00096 while (m_isRunning)
00097 {
00098 usleep(1000);
00099
00100
00101 if (!m_pendingRequest)
00102 continue;
00103
00104
00105 usleep(waitTime);
00106
00107 int chanid = GetChannelID(m_requestedChannel);
00108
00109
00110 if (chanid < 0)
00111 continue;
00112
00113
00114 if (UseOnAirGuide((uint)chanid))
00115 {
00116 RequestEPG(m_requestedChannel);
00117 m_pendingRequest = false;
00118 }
00119 else
00120 {
00121 VERBOSE(VB_EIT, LOC + QString("EPG disabled for %1.")
00122 .arg(m_requestedChannel));
00123 m_dbox2channel->EPGFinished();
00124 }
00125 }
00126 VERBOSE(VB_EIT, LOC + "Exiting Thread....");
00127 }
00128
00129
00130 void DBox2EPG::ScheduleRequestEPG(const QString& channelNumber)
00131 {
00132 m_requestedChannel = QDeepCopy<QString>(channelNumber);
00133 m_pendingRequest = true;
00134 }
00135
00136 void DBox2EPG::RequestEPG(const QString& channelNumber)
00137 {
00138
00139 QString requestString, channelName, dbox2ChannelID;
00140 channelName = m_dbox2channel->GetChannelNameFromNumber(channelNumber);
00141 dbox2ChannelID = m_dbox2channel->GetChannelID(channelName);
00142 requestString = QString("/control/epg?id=%1").arg(dbox2ChannelID);
00143
00144 VERBOSE(VB_EIT, LOC +
00145 QString("Requesting EPG for channel %2 (%3): %4%5")
00146 .arg(m_cardid)
00147 .arg(channelNumber)
00148 .arg(channelName)
00149 .arg(m_dbox2options->host)
00150 .arg(requestString));
00151
00152
00153 QHttpRequestHeader header("GET", requestString);
00154 header.setValue("Host", m_dbox2options->host);
00155
00156 m_currentEPGRequestChannel = channelNumber;
00157 m_currentEPGRequestID = http->request(header);
00158 }
00159
00160
00161 void DBox2EPG::UpdateDB(uint chanid,
00162 const QDateTime &startTime,
00163 const QDateTime &endTime,
00164 const QString &title,
00165 const QString &description,
00166 const QString &category)
00167 {
00168 MSqlQuery query(MSqlQuery::InitCon());
00169
00170
00171 query.prepare("DELETE FROM program "
00172 "WHERE chanid = :CHANID AND "
00173 " starttime = :STARTTIME");
00174
00175 query.bindValue(":CHANID", chanid);
00176 query.bindValue(":STARTTIME", startTime);
00177
00178 if (!query.exec())
00179 MythContext::DBError("Deleting old program", query);
00180
00181
00182 query.prepare("INSERT INTO program "
00183 " (chanid, starttime, endtime, "
00184 " title, subtitle, description, "
00185 " category, airdate, stars) "
00186 "VALUES "
00187 " (:CHANID, :STARTTIME, :ENDTIME, "
00188 " :TITLE, :SUBTITLE, :DESCRIPTION, "
00189 " :CATEGORY,:AIRDATE, :STARS)");
00190
00191 query.bindValue(":CHANID", chanid);
00192 query.bindValue(":STARTTIME", startTime);
00193 query.bindValue(":ENDTIME", endTime);
00194 query.bindValue(":TITLE", title.utf8());
00195 query.bindValue(":SUBTITLE", "");
00196 query.bindValue(":DESCRIPTION", description.utf8());
00197 query.bindValue(":CATEGORY", category.utf8());
00198 query.bindValue(":AIRDATE", "0");
00199 query.bindValue(":STARS", "0");
00200
00201 if (!query.exec())
00202 MythContext::DBError("Saving new program", query);
00203 }
00204
00212 void DBox2EPG::httpRequestFinished(int requestID, bool error)
00213 {
00214 if (error)
00215 {
00216 VERBOSE(VB_EIT, LOC + "Reading EPG failed.");
00217 m_dbox2channel->EPGFinished();
00218 return;
00219 }
00220
00221 if (requestID != m_currentEPGRequestID)
00222 {
00223 VERBOSE(VB_EIT, LOC + "Got EPG for old channel. Ignoring");
00224 return;
00225 }
00226
00227 QByteArray buffer = http->readAll();
00228 int size = buffer.size();
00229 int chanid = GetChannelID(m_currentEPGRequestChannel);
00230
00231 VERBOSE(VB_EIT, LOC + "EPG received. " +
00232 QString("Parsing %2 bytes...").arg(size));
00233
00234
00235 int showCount = 0;
00236 int index = 0;
00237
00238 QDateTime startTime;
00239 QDateTime endTime;
00240 QString epgID, title, category, desc;
00241
00242 while (index < size)
00243 {
00244
00245 QString line = ParseNextLine(buffer, index, size);
00246
00247 if (line.isEmpty())
00248 continue;
00249
00250
00251 epgID = line.section(" ", 0, 0);
00252 startTime.setTime_t(line.section(" ", 1, 1).toInt());
00253 endTime = startTime.addSecs(line.section(" ", 2, 2).toInt());
00254
00255 title = ParseNextLine(buffer, index, size);
00256 category = ParseNextLine(buffer, index, size);
00257 desc = ParseNextLine(buffer, index, size);
00258
00259
00260
00261 VERBOSE(VB_EIT, LOC +
00262 QString("Found show. Start Time: %1, End Time: %2, "
00263 "Title: %3, Description: %4.")
00264 .arg(m_cardid)
00265 .arg(startTime.toString()).arg(endTime.toString())
00266 .arg(title).arg(desc));
00267
00268
00269 UpdateDB(chanid, startTime, endTime, title, desc, category);
00270
00271 showCount++;
00272 }
00273
00274 VERBOSE(VB_EIT, LOC + "EPG parsing done. " +
00275 QString("Got %2 shows for channel %3.")
00276 .arg(showCount).arg(m_currentEPGRequestChannel));
00277
00278 m_dbox2channel->EPGFinished();
00279 }
00280
00281 QString DBox2EPG::ParseNextLine(const QByteArray &buf, int &pos, int size)
00282 {
00283 QString string;
00284 while (pos < size)
00285 {
00286 char current = buf[pos];
00287 pos++;
00288 if (current == '\n')
00289 break;
00290 string += current;
00291 }
00292 return string;
00293 }
00294
00295 int DBox2EPG::GetChannelID(const QString& channum)
00296 {
00297 MSqlQuery query(MSqlQuery::InitCon());
00298
00299 query.prepare(
00300 "SELECT chanid "
00301 "FROM channel, cardinput "
00302 "WHERE cardid = :CARDID AND "
00303 " channum = :CHANNUM AND "
00304 " channel.sourceid = cardinput.sourceid");
00305
00306 query.bindValue(":CARDID", m_cardid);
00307 query.bindValue(":CHANNUM", channum);
00308
00309 if (query.exec() && query.isActive())
00310 {
00311 if (query.next())
00312 return query.value(0).toInt();
00313
00314 VERBOSE(VB_IMPORTANT, QString("DBox2EPG::GetChannelID(): channum "
00315 "'%1' not found in DB").arg(channum));
00316 }
00317 else
00318 {
00319 MythContext::DBError("DBox2EPG::GetChannelID()", query);
00320 }
00321 return -1;
00322 }
00323
00328 bool DBox2EPG::UseOnAirGuide(uint chanid)
00329 {
00330 MSqlQuery query(MSqlQuery::InitCon());
00331
00332 query.prepare(
00333 "SELECT useonairguide "
00334 "FROM channel "
00335 "WHERE chanid = :CHANID");
00336
00337 query.bindValue(":CHANID", chanid);
00338
00339 if (query.exec() && query.isActive())
00340 {
00341 if (query.next())
00342 return (bool) query.value(0).toInt();
00343
00344 VERBOSE(VB_IMPORTANT, QString("DBox2EPG::UseOnAirGuide(): chanid "
00345 "'%1' not found in DB").arg(chanid));
00346 }
00347 else
00348 {
00349 MythContext::DBError("DBox2EPG::UseOnAirGuide()", query);
00350 }
00351 return false;
00352 }