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 {
00041 parent->insertNewsArticle(this);
00042 m_title = title;
00043 m_desc = desc;
00044 m_parent = parent;
00045 m_articleURL = articleURL;
00046 }
00047
00048 NewsArticle::~NewsArticle()
00049 {
00050
00051 }
00052
00053 const QString& NewsArticle::title() const
00054 {
00055 return m_title;
00056 }
00057
00058 const QString& NewsArticle::description() const
00059 {
00060 return m_desc;
00061 }
00062
00063
00064 NewsSite::NewsSite(const QString& name,
00065 const QString& url,
00066 const QDateTime& updated)
00067 : QObject()
00068 {
00069 m_url = url;
00070 m_name = name;
00071 m_updated = updated;
00072 m_state = NewsSite::Success;
00073
00074 m_destDir = MythContext::GetConfDir();
00075 m_destDir += "/MythFlix";
00076
00077 m_articleList.setAutoDelete(true);
00078 m_articleList.clear();
00079
00080 m_data.resize(0);
00081 m_urlOp = new QUrlOperator(m_url);
00082
00083 }
00084
00085 NewsSite::~NewsSite()
00086 {
00087 m_urlOp->stop();
00088 delete m_urlOp;
00089 m_articleList.clear();
00090 }
00091
00092 void NewsSite::insertNewsArticle(NewsArticle* item)
00093 {
00094 m_articleList.append(item);
00095 }
00096
00097 void NewsSite::clearNewsArticles()
00098 {
00099 m_articleList.clear();
00100 }
00101
00102 const QString& NewsSite::url() const
00103 {
00104 return m_url;
00105 }
00106
00107 const QString& NewsSite::name() const
00108 {
00109 return m_name;
00110 }
00111
00112 QString NewsSite::description() const
00113 {
00114 QString desc(m_desc+"\n"+m_errorString);
00115 return desc;
00116 }
00117
00118 const QDateTime& NewsSite::lastUpdated() const
00119 {
00120 return m_updated;
00121 }
00122
00123 unsigned int NewsSite::timeSinceLastUpdate() const
00124 {
00125 QDateTime curTime(QDateTime::currentDateTime());
00126 unsigned int min = m_updated.secsTo(curTime)/60;
00127 return min;
00128 }
00129
00130 NewsArticle::List& NewsSite::articleList()
00131 {
00132 return m_articleList;
00133 }
00134
00135 void NewsSite::retrieve()
00136 {
00137 stop();
00138
00139 connect(m_urlOp, SIGNAL(data(const QByteArray&, QNetworkOperation*)),
00140 this, SLOT(slotGotData(const QByteArray&, QNetworkOperation*)));
00141 connect(m_urlOp, SIGNAL(finished(QNetworkOperation*)),
00142 this, SLOT(slotFinished(QNetworkOperation*)));
00143
00144 m_state = NewsSite::Retrieving;
00145 m_data.resize(0);
00146 m_articleList.clear();
00147 m_urlOp->get(m_url);
00148 }
00149
00150
00151 void NewsSite::stop()
00152 {
00153 m_urlOp->stop();
00154
00155 disconnect(m_urlOp, SIGNAL(data(const QByteArray&, QNetworkOperation*)),
00156 this, SLOT(slotGotData(const QByteArray&, QNetworkOperation*)));
00157 disconnect(m_urlOp, SIGNAL(finished(QNetworkOperation*)),
00158 this, SLOT(slotFinished(QNetworkOperation*)));
00159 }
00160
00161 bool NewsSite::successful() const
00162 {
00163 return (m_state == NewsSite::Success);
00164 }
00165
00166 QString NewsSite::errorMsg() const
00167 {
00168 return m_errorString;
00169 }
00170
00171 void NewsSite::slotFinished(QNetworkOperation* op)
00172 {
00173 if (op->state() == QNetworkProtocol::StDone &&
00174 op->errorCode() == QNetworkProtocol::NoError) {
00175
00176 QFile xmlFile(m_destDir+QString("/")+m_name);
00177 if (xmlFile.open( IO_WriteOnly )) {
00178 QDataStream stream( &xmlFile );
00179 stream.writeRawBytes(m_data.data(), m_data.size());
00180 xmlFile.close();
00181 m_updated = QDateTime::currentDateTime();
00182 m_state = NewsSite::Success;
00183 }
00184 else {
00185 m_state = NewsSite::WriteFailed;
00186 VERBOSE(VB_IMPORTANT, "MythNews: NewsEngine: Write failed");
00187 }
00188 }
00189 else {
00190 m_state = NewsSite::RetrieveFailed;
00191 }
00192
00193 stop();
00194
00195 emit finished(this);
00196 }
00197
00198 void NewsSite::process()
00199 {
00200 m_articleList.clear();
00201
00202 if (m_state == RetrieveFailed)
00203 m_errorString = tr("Retrieve Failed. ");
00204 else
00205 m_errorString = "";
00206
00207 QDomDocument domDoc;
00208
00209 QFile xmlFile(m_destDir+QString("/")+m_name);
00210 if (!xmlFile.exists()) {
00211 new NewsArticle(this, tr("Failed to retrieve news"), "", "");
00212 m_errorString += tr("No Cached News");
00213 return;
00214 }
00215
00216 if (!xmlFile.open(IO_ReadOnly)) {
00217 new NewsArticle(this, tr("Failed to retrieve news"), "", "");
00218 cerr << "MythNews: NewsEngine: failed to open xmlfile" << endl;
00219 return;
00220 }
00221
00222 if (!domDoc.setContent(&xmlFile)) {
00223 new NewsArticle(this, tr("Failed to retrieve news"), "", "");
00224 cerr << "MythNews: NewsEngine: failed to set content from xmlfile" << endl;
00225 m_errorString += tr("Failed to read downloaded file");
00226 return;
00227 }
00228
00229
00230 if (m_state == RetrieveFailed)
00231 m_errorString += tr("Showing Cached News");
00232
00233 QDomNode channelNode = domDoc.documentElement().namedItem(QString::fromLatin1("channel"));
00234
00235 m_desc = channelNode.namedItem(QString::fromLatin1("description")).toElement().text().simplifyWhiteSpace();
00236
00237 QDomNodeList items = domDoc.elementsByTagName(QString::fromLatin1("item"));
00238
00239 QDomNode itemNode;
00240 QString title, description, url;
00241 for (unsigned int i = 0; i < items.count(); i++) {
00242 itemNode = items.item(i);
00243 title = itemNode.namedItem(QString::fromLatin1("title")).toElement().text().simplifyWhiteSpace();
00244 QDomNode descNode = itemNode.namedItem(QString::fromLatin1("description"));
00245 if (!descNode.isNull())
00246 {
00247 description = descNode.toElement().text().simplifyWhiteSpace();
00248 ReplaceHtmlChar(description);
00249 }
00250 else
00251 description = QString::null;
00252 QDomNode linkNode = itemNode.namedItem(QString::fromLatin1("link"));
00253 if (!linkNode.isNull())
00254 url = linkNode.toElement().text().simplifyWhiteSpace();
00255 else
00256 url = QString::null;
00257
00258
00259 new NewsArticle(this, title, description, url);
00260 }
00261
00262 xmlFile.close();
00263
00264 }
00265
00266 void NewsSite::slotGotData(const QByteArray& data,
00267 QNetworkOperation* op)
00268 {
00269 if (op)
00270 {
00271 const char *charData = data.data();
00272 int len = data.count();
00273
00274 int size = m_data.size();
00275 m_data.resize(size + len);
00276 memcpy(m_data.data()+size, charData, len);
00277 }
00278 }
00279
00280 void NewsSite::ReplaceHtmlChar(QString &s)
00281 {
00282 s.replace("&", "&");
00283 s.replace("<", "<");
00284 s.replace(">", ">");
00285 s.replace(""", "\"");
00286 s.replace("'", "\'");
00287 s.replace("…",QChar(8230));
00288 s.replace("é",QChar(233));
00289 }
00290