00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <iostream>
00023
00024 #include <qfile.h>
00025 #include <qdatastream.h>
00026 #include <qdom.h>
00027 #include <qurloperator.h>
00028
00029 extern "C" {
00030 #include <stdlib.h>
00031 }
00032
00033 #include "newsengine.h"
00034 #include <mythtv/mythcontext.h>
00035
00036 using namespace std;
00037
00038 NewsArticle::NewsArticle(NewsSite *parent, const QString& title,
00039 const QString& desc, const QString& articleURL,
00040 const QString& thumbnail, const QString& mediaURL,
00041 const QString& enclosure)
00042 {
00043 parent->insertNewsArticle(this);
00044 m_title = title;
00045 m_desc = desc;
00046 m_parent = parent;
00047 m_articleURL = articleURL;
00048 m_thumbnail = thumbnail;
00049 m_mediaURL = mediaURL;
00050 m_enclosure = enclosure;
00051 }
00052
00053 NewsArticle::~NewsArticle()
00054 {
00055
00056 }
00057
00058 NewsSite::NewsSite(const QString& name,
00059 const QString& url,
00060 const QDateTime& updated)
00061 : QObject()
00062 {
00063 m_url = url;
00064 m_name = name;
00065 m_updated = updated;
00066 m_state = NewsSite::Success;
00067
00068 m_destDir = MythContext::GetConfDir();
00069 m_destDir += "/MythNews";
00070
00071 m_articleList.setAutoDelete(true);
00072 m_articleList.clear();
00073
00074 m_data.resize(0);
00075 m_urlOp = new QUrlOperator(m_url);
00076
00077 connect(m_urlOp, SIGNAL(data(const QByteArray&, QNetworkOperation*)),
00078 this, SLOT(slotGotData(const QByteArray&, QNetworkOperation*)));
00079 connect(m_urlOp, SIGNAL(finished(QNetworkOperation*)),
00080 this, SLOT(slotFinished(QNetworkOperation*)));
00081 }
00082
00083 NewsSite::~NewsSite()
00084 {
00085 m_urlOp->disconnect(this, 0, 0, 0);
00086 m_urlOp->stop();
00087 m_urlOp->deleteLater();
00088 m_articleList.clear();
00089 }
00090
00091 void NewsSite::insertNewsArticle(NewsArticle* item)
00092 {
00093 m_articleList.append(item);
00094 }
00095
00096 void NewsSite::clearNewsArticles()
00097 {
00098 m_articleList.clear();
00099 }
00100
00101 const QString& NewsSite::url() const
00102 {
00103 return m_url;
00104 }
00105
00106 const QString& NewsSite::name() const
00107 {
00108 return m_name;
00109 }
00110
00111 QString NewsSite::description() const
00112 {
00113 QString desc(m_desc+"\n"+m_errorString);
00114 return desc;
00115 }
00116
00117 const QString& NewsSite::imageURL() const
00118 {
00119 return m_imageURL;
00120 }
00121
00122 const QDateTime& NewsSite::lastUpdated() const
00123 {
00124 return m_updated;
00125 }
00126
00127 unsigned int NewsSite::timeSinceLastUpdate() const
00128 {
00129 QDateTime curTime(QDateTime::currentDateTime());
00130 unsigned int min = m_updated.secsTo(curTime)/60;
00131 return min;
00132 }
00133
00134 NewsArticle::List& NewsSite::articleList()
00135 {
00136 return m_articleList;
00137 }
00138
00139 void NewsSite::retrieve()
00140 {
00141 stop();
00142
00143 m_state = NewsSite::Retrieving;
00144 m_data.resize(0);
00145 m_articleList.clear();
00146 m_urlOp->get(m_url);
00147 }
00148
00149 void NewsSite::stop()
00150 {
00151 m_urlOp->stop();
00152 }
00153
00154 bool NewsSite::successful() const
00155 {
00156 return (m_state == NewsSite::Success);
00157 }
00158
00159 QString NewsSite::errorMsg() const
00160 {
00161 return m_errorString;
00162 }
00163
00164 void NewsSite::slotFinished(QNetworkOperation* op)
00165 {
00166 if (op->state() == QNetworkProtocol::StDone &&
00167 op->errorCode() == QNetworkProtocol::NoError)
00168 {
00169
00170 QFile xmlFile(m_destDir+QString("/")+m_name);
00171 if (xmlFile.open( IO_WriteOnly )) {
00172 QDataStream stream( &xmlFile );
00173 stream.writeRawBytes(m_data.data(), m_data.size());
00174 xmlFile.close();
00175 m_updated = QDateTime::currentDateTime();
00176 m_state = NewsSite::Success;
00177 }
00178 else
00179 {
00180 m_state = NewsSite::WriteFailed;
00181 VERBOSE(VB_IMPORTANT, "MythNews: NewsEngine: Write failed");
00182 }
00183 }
00184 else
00185 {
00186 m_state = NewsSite::RetrieveFailed;
00187 }
00188
00189 emit finished(this);
00190 }
00191
00192 void NewsSite::process()
00193 {
00194 m_articleList.clear();
00195
00196 if (m_state == RetrieveFailed)
00197 m_errorString = tr("Retrieve Failed. ");
00198 else
00199 m_errorString = "";
00200
00201 QDomDocument domDoc;
00202
00203 QFile xmlFile(m_destDir+QString("/")+m_name);
00204 if (!xmlFile.exists()) {
00205 new NewsArticle(this, tr("Failed to retrieve news"), "", "", "", "", "");
00206 m_errorString += tr("No Cached News");
00207 return;
00208 }
00209
00210 if (!xmlFile.open(IO_ReadOnly)) {
00211 new NewsArticle(this, tr("Failed to retrieve news"), "", "", "", "", "");
00212 VERBOSE(VB_IMPORTANT, "MythNews: NewsEngine: failed to open xmlfile");
00213 return;
00214 }
00215
00216 if (!domDoc.setContent(&xmlFile)) {
00217 new NewsArticle(this, tr("Failed to retrieve news"), "", "", "", "", "");
00218 VERBOSE(VB_IMPORTANT, "MythNews: NewsEngine: failed to set content from xmlfile");
00219 m_errorString += tr("Failed to read downloaded file");
00220 return;
00221 }
00222
00223
00224 if (m_state == RetrieveFailed)
00225 m_errorString += tr("Showing Cached News");
00226
00227 QDomNode channelNode = domDoc.documentElement().namedItem(QString::fromLatin1("channel"));
00228
00229 m_desc = channelNode.namedItem(QString::fromLatin1("description")).toElement().text().simplifyWhiteSpace();
00230
00231 QDomNode imageNode = channelNode.namedItem(QString::fromLatin1("image"));
00232 if (!imageNode.isNull())
00233 m_imageURL = imageNode.namedItem(QString::fromLatin1("url")).toElement().text().simplifyWhiteSpace();
00234
00235 QDomNodeList items = domDoc.elementsByTagName(QString::fromLatin1("item"));
00236
00237 QDomNode itemNode;
00238 QString title, description, url, thumbnail, mediaurl, enclosure, imageURL, enclosure_type;
00239 for (unsigned int i = 0; i < items.count(); i++) {
00240 itemNode = items.item(i);
00241 title = itemNode.namedItem(QString::fromLatin1("title")).toElement().text().simplifyWhiteSpace();
00242 if (!title.isNull())
00243 ReplaceHtmlChar(title);
00244
00245 QDomNode descNode = itemNode.namedItem(QString::fromLatin1("description"));
00246 if (!descNode.isNull())
00247 {
00248 description = descNode.toElement().text().simplifyWhiteSpace();
00249 ReplaceHtmlChar(description);
00250 }
00251 else
00252 description = QString::null;
00253
00254 QDomNode linkNode = itemNode.namedItem(QString::fromLatin1("link"));
00255 if (!linkNode.isNull())
00256 url = linkNode.toElement().text().simplifyWhiteSpace();
00257 else
00258 url = QString::null;
00259
00260 QDomNode enclosureNode = itemNode.namedItem(QString::fromLatin1("enclosure"));
00261 if (!enclosureNode.isNull())
00262 {
00263 QDomAttr enclosureURL = enclosureNode.toElement().attributeNode("url");
00264 if (!enclosureURL.isNull())
00265 enclosure = enclosureURL.value();
00266
00267 QDomAttr enclosureType = enclosureNode.toElement().attributeNode("type");
00268 if (!enclosureType.isNull())
00269 enclosure_type = enclosureType.value();
00270
00271
00272 } else
00273 enclosure = QString::null;
00274
00275
00276
00277
00278
00279 QDomNode mediaGroup = itemNode.namedItem(QString::fromLatin1("media:group"));
00280 if (!mediaGroup.isNull())
00281 itemNode = mediaGroup;
00282
00283 QDomNode thumbNode = itemNode.namedItem(QString::fromLatin1("media:thumbnail"));
00284 if (!thumbNode.isNull())
00285 {
00286 QDomAttr thumburl = thumbNode.toElement().attributeNode("url");
00287 if (!thumburl.isNull())
00288 thumbnail = thumburl.value();
00289
00290 } else
00291 thumbnail = QString::null;
00292
00293 QDomNode playerNode = itemNode.namedItem(QString::fromLatin1("media:player"));
00294 if (!playerNode.isNull())
00295 {
00296 QDomAttr mediaURL = playerNode.toElement().attributeNode("url");
00297 if (!mediaURL.isNull())
00298 mediaurl = mediaURL.value();
00299
00300 } else
00301 mediaurl = QString::null;
00302
00303
00304 descNode = itemNode.namedItem(QString::fromLatin1("media:description"));
00305 if (!descNode.isNull())
00306 description = descNode.toElement().text().simplifyWhiteSpace();
00307
00308 if (!enclosure)
00309 {
00310 QDomNode contentNode = itemNode.namedItem(QString::fromLatin1("media:content"));
00311 if (!contentNode.isNull())
00312 {
00313 QDomAttr enclosureURL = contentNode.toElement().attributeNode("url");
00314 if (!enclosureURL.isNull())
00315 enclosure = enclosureURL.value();
00316
00317 QDomAttr enclosureType = contentNode.toElement().attributeNode("type");
00318 if (!enclosureType.isNull())
00319 enclosure_type = enclosureType.value();
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 }
00344 }
00345 new NewsArticle(this, title, description, url, thumbnail, mediaurl, enclosure);
00346 }
00347
00348 xmlFile.close();
00349
00350 }
00351
00352 void NewsSite::slotGotData(const QByteArray& data,
00353 QNetworkOperation* op)
00354 {
00355 if (op)
00356 {
00357 const char *charData = data.data();
00358 int len = data.count();
00359
00360 int size = m_data.size();
00361 m_data.resize(size + len);
00362 memcpy(m_data.data()+size, charData, len);
00363 }
00364 }
00365
00366 void NewsSite::ReplaceHtmlChar(QString &s)
00367 {
00368 s.replace("&", "&");
00369 s.replace("<", "<");
00370 s.replace(">", ">");
00371 s.replace(""", "\"");
00372 s.replace("'", "\'");
00373 s.replace("…",QChar(8230));
00374 s.replace("é",QChar(233));
00375 s.replace("—", QChar(8212));
00376 s.replace(" ", " ");
00377 s.replace(" ", QChar(160));
00378 s.replace("á", QChar(225));
00379 s.replace("‘", QChar(8216));
00380 s.replace("’", QChar(8217));
00381 s.replace("'", "\'");
00382 s.replace("–", QChar(8211));
00383
00384 s.replace("ä", QChar(0x00e4));
00385 s.replace("ö", QChar(0x00f6));
00386 s.replace("ü", QChar(0x00fc));
00387 s.replace("Ä", QChar(0x00c4));
00388 s.replace("Ö", QChar(0x00d6));
00389 s.replace("Ü", QChar(0x00dc));
00390 s.replace("ß", QChar(0x00df));
00391 }
00392