rendered paste bodyIndex: mythnews/mythnews/newsengine.cpp
===================================================================
--- mythnews/mythnews/newsengine.cpp (revision 18874)
+++ mythnews/mythnews/newsengine.cpp (working copy)
@@ -8,8 +8,6 @@
// QT headers
#include <QFile>
#include <QDataStream>
-#include <q3urloperator.h>
-#include <q3network.h>
// Myth headers
#include <mythtv/mythcontext.h>
@@ -41,38 +39,41 @@
{
}
-NewsSite::NewsSite(const QString &name,
- const QString &url,
+NewsArticle::NewsArticle() :
+ m_title(QString::null),
+ m_desc(QString::null),
+ m_articleURL(QString::null),
+ m_thumbnail(QString::null),
+ m_mediaURL(QString::null),
+ m_enclosure(QString::null)
+{
+}
+
+NewsSite::NewsSite(const QString &name,
+ const QString &url,
const QDateTime &updated,
- const bool &podcast)
- : QObject()
+ const bool podcast) :
+ QObject(), m_name(name), m_url(url), m_urlReq(url),
+ m_desc(QString::null), m_updated(updated),
+ m_destDir(GetConfDir()+"/MythNews"),
+ /*m_data(),*/
+ m_state(NewsSite::Success),
+ m_errorString(QString::null),
+ m_imageURL(""),
+ m_podcast(podcast)
{
- m_url = url;
- m_name = name;
- m_updated = updated;
- m_podcast = podcast;
- m_state = NewsSite::Success;
+}
- m_destDir = GetConfDir();
- m_destDir += "/MythNews";
-
+void NewsSite::deleteLater()
+{
+ HttpPool::GetSingleton()->RemoveListener(this);
m_articleList.clear();
-
- m_data.resize(0);
- m_urlOp = new Q3UrlOperator(m_url);
-
- connect(m_urlOp, SIGNAL(data(const QByteArray&, Q3NetworkOperation*)),
- this, SLOT(slotGotData(const QByteArray&, Q3NetworkOperation*)));
- connect(m_urlOp, SIGNAL(finished(Q3NetworkOperation*)),
- this, SLOT(slotFinished(Q3NetworkOperation*)));
+ QObject::deleteLater();
}
NewsSite::~NewsSite()
{
- m_urlOp->disconnect(this, 0, 0, 0);
- m_urlOp->stop();
- m_urlOp->deleteLater();
- m_articleList.clear();
+ HttpPool::GetSingleton()->RemoveListener(this);
}
void NewsSite::insertNewsArticle(const NewsArticle &item)
@@ -131,16 +132,16 @@
void NewsSite::retrieve(void)
{
stop();
-
m_state = NewsSite::Retrieving;
m_data.resize(0);
m_articleList.clear();
- m_urlOp->get(m_url);
+ m_urlReq = QUrl(m_url);
+ HttpPool::GetSingleton()->AddURLRequest(m_urlReq, this);
}
void NewsSite::stop(void)
{
- m_urlOp->stop();
+ HttpPool::GetSingleton()->RemoveURLRequest(m_urlReq, this);
}
bool NewsSite::successful(void) const
@@ -153,16 +154,34 @@
return m_errorString;
}
-void NewsSite::slotFinished(Q3NetworkOperation* op)
+void NewsSite::Updated(QHttp::Error error,
+ const QUrl &url,
+ const QByteArray &data)
{
- if (op->state() == Q3NetworkProtocol::StDone &&
- op->errorCode() == Q3NetworkProtocol::NoError)
+ if (url != m_urlReq)
{
+ return;
+ }
- QFile xmlFile(m_destDir+QString("/")+m_name);
- if (xmlFile.open( QIODevice::WriteOnly )) {
- QDataStream stream( &xmlFile );
- stream.writeRawData(m_data.constData(), m_data.size());
+ if (QHttp::NoError != error)
+ {
+ m_state = NewsSite::RetrieveFailed;
+ emit finished(this);
+ return;
+ }
+
+ m_data = data;
+
+ if (m_name.isEmpty())
+ {
+ m_state = NewsSite::WriteFailed;
+ }
+ else
+ {
+ QFile xmlFile(QString("%1/%2").arg(m_destDir).arg(m_name));
+ if (xmlFile.open(QIODevice::WriteOnly))
+ {
+ xmlFile.write(m_data);
xmlFile.close();
m_updated = QDateTime::currentDateTime();
m_state = NewsSite::Success;
@@ -170,14 +189,12 @@
else
{
m_state = NewsSite::WriteFailed;
- VERBOSE(VB_IMPORTANT, "MythNews: NewsEngine: Write failed");
}
}
- else
- {
- m_state = NewsSite::RetrieveFailed;
- }
+ if (NewsSite::WriteFailed == m_state)
+ VERBOSE(VB_IMPORTANT, "MythNews: NewsEngine: Write failed");
+
emit finished(this);
}
@@ -402,20 +419,6 @@
}
}
-void NewsSite::slotGotData(const QByteArray &data,
- Q3NetworkOperation* op)
-{
- if (op)
- {
- const char *charData = data.data();
- int len = data.count();
-
- int size = m_data.size();
- m_data.resize(size + len);
- memcpy(m_data.data()+size, charData, len);
- }
-}
-
void NewsSite::ReplaceHtmlChar(QString &s)
{
s.replace("&", "&");
Index: mythnews/mythnews/newsengine.h
===================================================================
--- mythnews/mythnews/newsengine.h (revision 18874)
+++ mythnews/mythnews/newsengine.h (working copy)
@@ -15,6 +15,8 @@
class Q3NetworkOperation;
class NewsSite;
+#include "httppool.h"
+
class NewsArticle
{
public:
@@ -25,6 +27,7 @@
const QString &thumbnail, const QString &mediaURL,
const QString &enclosure);
NewsArticle(const QString &title);
+ NewsArticle();
QString title(void) const { return m_title; }
QString description(void) const { return m_desc; }
@@ -45,7 +48,7 @@
// -------------------------------------------------------
-class NewsSite : public QObject
+class NewsSite : public QObject, public HttpListener
{
Q_OBJECT
@@ -72,8 +75,9 @@
}
};
- NewsSite(const QString &name, const QString &url,
- const QDateTime &updated, const bool &podcast);
+ NewsSite(const QString &name, const QString &url,
+ const QDateTime &updated, const bool podcast);
+ virtual void deleteLater();
QString url(void) const;
QString name(void) const;
@@ -96,11 +100,16 @@
bool successful(void) const;
QString errorMsg(void) const;
+ virtual void Updated(QHttp::Error error,
+ const QUrl &url,
+ const QByteArray &data);
+
private:
~NewsSite();
QString m_name;
QString m_url;
+ QUrl m_urlReq;
QString m_desc;
QDateTime m_updated;
QString m_destDir;
@@ -111,19 +120,11 @@
bool m_podcast;
NewsArticle::List m_articleList;
- Q3UrlOperator *m_urlOp;
-
void ReplaceHtmlChar( QString &s);
signals:
void finished(NewsSite* item);
-
- private slots:
-
- void slotFinished(Q3NetworkOperation*);
- void slotGotData(const QByteArray &data,
- Q3NetworkOperation* op);
};
class NewsSiteItem
Index: mythnews/mythnews/httppool.cpp
===================================================================
--- mythnews/mythnews/httppool.cpp (revision 0)
+++ mythnews/mythnews/httppool.cpp (revision 0)
@@ -0,0 +1,155 @@
+#include "httppool.h"
+#include "httphandler.h"
+
+// Myth headers
+#include <mythverbose.h>
+
+#define LOC QString("HttpPool: ")
+#define LOC_WARN QString("HttpPool, Warning: ")
+#define LOC_ERR QString("HttpPool, Error: ")
+
+HttpPool *HttpPool::singleton;
+
+HttpPool::HttpPool(uint max_connections) : m_maxConnections(max_connections)
+{
+}
+
+HttpPool::~HttpPool()
+{
+ while (!m_hostToHandler.empty())
+ {
+ HostToHandler::iterator it = m_hostToHandler.begin();
+ HttpHandler *h = *it;
+ m_hostToHandler.erase(it);
+ h->deleteLater();
+ }
+}
+
+void HttpPool::AddURLRequest(const QUrl &url, HttpListener *listener)
+{
+ QMutexLocker locker(&m_lock);
+
+ VERBOSE(VB_NETWORK, LOC + QString("AddUrlRequest(%1, 0x%2)")
+ .arg(url.toString()).arg((uint64_t)listener,0,16));
+
+ bool in_queue = m_urlToListener.find(url) != m_urlToListener.end();
+
+ m_urlToListener.insert(url, listener);
+ set<HttpListener*>::iterator lit = m_listeners.find(listener);
+ if (lit == m_listeners.end())
+ m_listeners.insert(listener);
+
+ if (in_queue)
+ return;
+
+ HostToHandler::iterator it = m_hostToHandler.find(url.host());
+
+ if (it != m_hostToHandler.end())
+ {
+ (*it)->AddURLRequest(url);
+ }
+ else if ((uint)m_hostToHandler.size() < m_maxConnections)
+ {
+ HttpHandler *hh = new HttpHandler(this);
+ m_hostToHandler[url.host()] = hh;
+ hh->AddURLRequest(url);
+ }
+ else
+ {
+ HostToHandler::iterator it = m_hostToHandler.begin();
+ for (; it != m_hostToHandler.end(); ++it)
+ {
+ if (!(*it)->HasPendingRequests())
+ break;
+ }
+ if (it != m_hostToHandler.end())
+ {
+ HttpHandler *hh = *it;
+ m_hostToHandler.erase(it);
+ m_hostToHandler[url.host()] = hh;
+ hh->AddURLRequest(url);
+ }
+ else
+ {
+ m_httpQueue.push_back(HttpRequest(url,listener));
+ }
+ }
+}
+
+void HttpPool::RemoveURLRequest(const QUrl &url, HttpListener *listener)
+{
+ QMutexLocker locker(&m_lock);
+
+ VERBOSE(VB_NETWORK, LOC + QString("RemoveUrlRequest(%1, 0x%2)")
+ .arg(url.toString()).arg((uint64_t)listener,0,16));
+}
+
+void HttpPool::RemoveListener(HttpListener *listener)
+{
+ QMutexLocker locker(&m_lock);
+
+ VERBOSE(VB_NETWORK, LOC + QString("RemoveListener(0x%1)")
+ .arg((uint64_t)listener,0,16));
+ set<HttpListener*>::iterator it = m_listeners.find(listener);
+ if (it != m_listeners.end())
+ m_listeners.erase(it);
+}
+
+void HttpPool::Update(QHttp::Error error,
+ const QUrl &url,
+ const QByteArray &data)
+{
+ QMutexLocker locker(&m_lock);
+
+ UrlToListener::iterator it = m_urlToListener.find(url);
+ for (; (it != m_urlToListener.end()) && (it.key() == url); ++it)
+ {
+ HttpListener *listener = *it;
+ if (m_listeners.find(listener) != m_listeners.end())
+ listener->Updated(error, url, data);
+ }
+ m_urlToListener.remove(url);
+}
+
+void HttpPool::Done(const QString &host, HttpHandler *handler)
+{
+ QMutexLocker locker(&m_lock);
+
+ VERBOSE(VB_NETWORK, LOC + QString("Done(%1, 0x%2)")
+ .arg(host).arg((uint64_t)handler,0,16));
+
+ HostToHandler::iterator it = m_hostToHandler.find(host);
+ if (handler != *it)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Done(%1, 0x%2)")
+ .arg(host).arg((uint64_t)handler,0,16));
+ return;
+ }
+
+ while (!m_httpQueue.empty())
+ {
+ QUrl url = m_httpQueue.front().m_url;
+ HttpListener *listener = m_httpQueue.front().m_listener;
+ m_httpQueue.pop_front();
+
+ if (m_listeners.find(listener) == m_listeners.end())
+ continue;
+
+ if (url.host() != host)
+ {
+ m_hostToHandler.erase(it);
+ m_hostToHandler[url.host()] = handler;
+ }
+ handler->AddURLRequest(url);
+ break;
+ }
+}
+
+HttpPool *HttpPool::GetSingleton()
+{
+ static QMutex lock;
+ QMutexLocker locker(&lock);
+ if (!singleton)
+ singleton = new HttpPool();
+ return singleton;
+}
Index: mythnews/mythnews/httphandler.cpp
===================================================================
--- mythnews/mythnews/httphandler.cpp (revision 0)
+++ mythnews/mythnews/httphandler.cpp (revision 0)
@@ -0,0 +1,151 @@
+#include "httphandler.h"
+#include "httppool.h"
+
+// Qt headers
+#include <QHttp>
+
+// Myth headers
+#include <mythverbose.h>
+
+#define LOC QString("HttpHandler: ")
+#define LOC_WARN QString("HttpHandler, Warning: ")
+#define LOC_ERR QString("HttpHandler, Error: ")
+
+//////////////////////////////////////////////////////////////////////
+
+HttpHandler::HttpHandler(HttpPool *pool) :
+ m_pool(pool), m_qhttp(new QHttp())
+{
+ connect(m_qhttp, SIGNAL(done(bool)),
+ this, SLOT(Done(bool)));
+ connect(m_qhttp, SIGNAL(requestFinished(int,bool)),
+ this, SLOT(RequestFinished(int,bool)));
+ connect(m_qhttp, SIGNAL(requestStarted(int)),
+ this, SLOT(RequestStarted(int)));
+ connect(m_qhttp, SIGNAL(stateChanged(int)),
+ this, SLOT(StateChanged(int)));
+ connect(m_qhttp, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)),
+ this, SLOT(ResponseHeaderReceived(const QHttpResponseHeader&)));
+}
+
+void HttpHandler::TeardownAll(void)
+{
+ QMutexLocker locker(&m_lock);
+
+ if (m_qhttp)
+ {
+ m_qhttp->abort();
+ m_qhttp->disconnect();
+ m_qhttp->deleteLater();
+ }
+ m_pool = NULL;
+ m_qhttp = NULL;
+}
+
+bool HttpHandler::HasPendingRequests(void) const
+{
+ QMutexLocker locker(&m_lock);
+ return m_qhttp->hasPendingRequests();
+}
+
+void HttpHandler::AddURLRequest(const QUrl &url)
+{
+ QMutexLocker locker(&m_lock);
+
+ if (!m_qhttp->hasPendingRequests())
+ Get(url);
+ else
+ m_urls.push_back(url);
+}
+
+void HttpHandler::Get(const QUrl &url)
+{
+ m_cur_url = url;
+ m_cur_status_id = 0;
+
+ m_qhttp->setHost(m_cur_url.host());
+
+ QString path = (m_cur_url.path().isEmpty()) ? "/" : m_cur_url.path();
+ m_cur_get_id = m_qhttp->get(path);
+}
+
+void HttpHandler::RemoveURLRequest(const QUrl &url)
+{
+ QMutexLocker locker(&m_lock);
+
+ URLQueue urls = m_urls;
+ m_urls.clear();
+ while (!urls.empty())
+ {
+ QUrl item = urls.front();
+ urls.pop_front();
+ if (item != url)
+ m_urls.push_back(item);
+ }
+
+ if (url == m_cur_url)
+ {
+ m_cur_url = QUrl();
+ m_cur_status_id = 0;
+ m_cur_get_id = 0;
+ m_qhttp->abort();
+ }
+}
+
+void HttpHandler::Done(bool error)
+{
+ QMutexLocker locker(&m_lock);
+
+ VERBOSE(VB_NETWORK, LOC + QString("Done(%1) url: %2")
+ .arg(error).arg(m_cur_url.toString()));
+
+ if (m_pool)
+ m_pool->Done(m_cur_url.host(), this);
+}
+
+void HttpHandler::ResponseHeaderReceived(const QHttpResponseHeader &resp)
+{
+ QMutexLocker locker(&m_lock);
+
+ VERBOSE(VB_NETWORK, LOC + QString("ResponseHeaderReceived(%1,%2) url: %3")
+ .arg(resp.statusCode()).arg(resp.reasonPhrase())
+ .arg(m_cur_url.toString()));
+ m_cur_status_id = resp.statusCode();
+}
+
+void HttpHandler::RequestFinished(int id, bool error)
+{
+ QMutexLocker locker(&m_lock);
+
+ VERBOSE(VB_NETWORK, LOC + QString("RequestFinished(%1,%2) url: %3")
+ .arg(id).arg(error).arg(m_cur_url.toString()));
+ if (error && m_pool)
+ m_pool->Update(m_qhttp->error(), m_cur_url, QByteArray());
+ else if ((id == m_cur_get_id) && m_pool)
+ m_pool->Update(QHttp::NoError, m_cur_url, m_qhttp->readAll());
+ else
+ return;
+
+ if (!m_urls.empty())
+ {
+ Get(m_urls.front());
+ m_urls.pop_front();
+ }
+}
+
+void HttpHandler::RequestStarted(int id)
+{
+ QMutexLocker locker(&m_lock);
+
+ VERBOSE(VB_NETWORK, LOC + QString("RequestStarted(%1) url: %2")
+ .arg(id).arg(m_cur_url.toString()));
+}
+
+void HttpHandler::StateChanged(int state)
+{
+ QMutexLocker locker(&m_lock);
+
+ VERBOSE(VB_NETWORK, LOC + QString("StateChanged(%1) url: %2")
+ .arg(state).arg(m_cur_url.toString()));
+}
+
Index: mythnews/mythnews/httppool.h
===================================================================
--- mythnews/mythnews/httppool.h (revision 0)
+++ mythnews/mythnews/httppool.h (revision 0)
@@ -0,0 +1,65 @@
+#ifndef _HTTP_POOL_H_
+#define _HTTP_POOL_H_
+
+// C++ headers
+#include <set>
+#include <deque>
+using namespace std;
+
+// Qt headers
+#include <QString>
+#include <QMutex>
+#include <QHttp>
+#include <QUrl>
+
+class HttpListener
+{
+ public:
+ virtual void Updated(QHttp::Error error,
+ const QUrl &url,
+ const QByteArray &data) = 0;
+};
+
+class HttpRequest
+{
+ public:
+ HttpRequest(const QUrl &url, HttpListener *listener) :
+ m_url(url), m_listener(listener) {}
+
+ QUrl m_url;
+ HttpListener *m_listener;
+};
+
+class HttpHandler;
+typedef QMap<QString,HttpHandler*> HostToHandler;
+typedef QMultiMap<QUrl,HttpListener*> UrlToListener;
+
+class HttpPool
+{
+ public:
+ HttpPool(uint max_connections = 20);
+ ~HttpPool();
+
+ void AddURLRequest(const QUrl &url, HttpListener *listener);
+ void RemoveURLRequest(const QUrl &url, HttpListener *listener);
+ void RemoveListener(HttpListener *listener);
+
+ static HttpPool *GetSingleton();
+
+ void Update(QHttp::Error error,
+ const QUrl &url,
+ const QByteArray &data);
+ void Done(const QString &host, HttpHandler *handler);
+
+ private:
+ mutable QMutex m_lock;
+ uint m_maxConnections;
+ deque<HttpRequest> m_httpQueue;
+ set<HttpListener*> m_listeners;
+ UrlToListener m_urlToListener;
+ HostToHandler m_hostToHandler;
+
+ static HttpPool *singleton;
+};
+
+#endif // _HTTP_POOL_H_
Index: mythnews/mythnews/mythnews.cpp
===================================================================
--- mythnews/mythnews/mythnews.cpp (revision 18874)
+++ mythnews/mythnews/mythnews.cpp (working copy)
@@ -179,35 +179,33 @@
return;
NewsSite *site = NULL;
- NewsArticle *article = NULL;
+ NewsArticle article;
if (GetFocusWidget() == m_articlesList)
{
- article = qVariantValue<NewsArticle*>(selected->GetData());
+ article = m_articles[selected];
if (m_sitesList->GetItemCurrent())
site = qVariantValue<NewsSite*>
- (m_sitesList->GetItemCurrent()->GetData());
+ (m_sitesList->GetItemCurrent()->GetData());
}
else
{
site = qVariantValue<NewsSite*>(selected->GetData());
if (m_articlesList->GetItemCurrent())
- article = qVariantValue<NewsArticle*>
- (m_articlesList->GetItemCurrent()->GetData());
+ article = m_articles[m_articlesList->GetItemCurrent()];
}
if (GetFocusWidget() == m_articlesList)
{
-
- if (article)
+ if (!article.title().isEmpty())
{
if (m_titleText)
- m_titleText->SetText(article->title());
+ m_titleText->SetText(article.title());
if (m_descText)
{
- QString artText = article->description();
+ QString artText = article.description();
// Replace paragraph and break HTML with newlines
if( artText.indexOf(QRegExp("</(p|P)>")) )
{
@@ -237,7 +235,7 @@
m_descText->SetText(artText);
}
- if (!article->thumbnail().isEmpty())
+ if (!article.thumbnail().isEmpty())
{
QString fileprefix = GetConfDir();
@@ -251,7 +249,7 @@
if (!dir.exists())
dir.mkdir(fileprefix);
- QString url = article->thumbnail();
+ QString url = article.thumbnail();
QString sFilename = QString("%1/%2")
.arg(fileprefix)
.arg(qChecksum(url.toLocal8Bit().constData(),
@@ -309,7 +307,7 @@
}
}
- if (!article->enclosure().isEmpty())
+ if (!article.enclosure().isEmpty())
{
if (!m_downloadImage->IsVisible())
m_downloadImage->Show();
@@ -317,7 +315,7 @@
else
m_downloadImage->Hide();
- if (!article->enclosure().isEmpty())
+ if (!article.enclosure().isEmpty())
{
if (!m_enclosureImage->IsVisible())
m_enclosureImage->Show();
@@ -547,13 +545,14 @@
return;
m_articlesList->Reset();
+ m_articles.clear();
NewsArticle::List::iterator it = site->articleList().begin();
for (; it != site->articleList().end(); ++it)
{
MythUIButtonListItem *item =
new MythUIButtonListItem(m_articlesList, (*it).title());
- item->SetData(qVariantFromValue(&(*it)));
+ m_articles[item] = *it;
}
}
@@ -567,13 +566,14 @@
return;
m_articlesList->Reset();
+ m_articles.clear();
NewsArticle::List::iterator it = site->articleList().begin();
for (; it != site->articleList().end(); ++it)
{
MythUIButtonListItem *item =
new MythUIButtonListItem(m_articlesList, (*it).title());
- item->SetData(qVariantFromValue(&(*it)));
+ m_articles[item] = *it;
}
updateInfoView(item);
@@ -689,82 +689,84 @@
void MythNews::slotViewArticle(MythUIButtonListItem *articlesListItem)
{
- if (articlesListItem && !articlesListItem->GetData().isNull())
- {
- NewsArticle *article = qVariantValue<NewsArticle*>
- (articlesListItem->GetData());
- if(article)
- {
- if (!article->enclosure().isEmpty())
- {
- QString cmdURL(article->enclosure());
- // Handle special cases for media here
- // YouTube: Fetch the mediaURL page and parse out the video URL
- if (cmdURL.contains("youtube.com"))
- {
- cmdURL = QString(article->mediaURL());
- QString mediaPage = HttpComms::getHttp(cmdURL);
- if (!mediaPage.isEmpty())
- {
- // If this breaks in the future, we are building the URL
- // to download a video. At this time, this requires
- // the video_id and the t argument
- // from the source HTML of the page
- int playerPos = mediaPage.indexOf("swfArgs") + 7;
+ QMap<MythUIButtonListItem*,NewsArticle>::const_iterator it =
+ m_articles.find(articlesListItem);
- int tArgStart = mediaPage.indexOf("\"t\": \"",
- playerPos) + 6;
- int tArgEnd = mediaPage.indexOf("\"", tArgStart);
- QString tArgString = mediaPage.mid(tArgStart,
- tArgEnd - tArgStart);
+ if (it == m_articles.end())
+ return;
- int vidStart = mediaPage.indexOf("\"video_id\": \"",
- playerPos) + 13;
- int vidEnd = mediaPage.indexOf("\"", vidStart);
- QString vidString = mediaPage.mid(vidStart,
- vidEnd - vidStart);
+ if ((*it).title().isEmpty())
+ return;
- cmdURL = QString("http://youtube.com/get_video.php"
- "?video_id=%2&t=%1")
- .arg(tArgString).arg(vidString);
- VERBOSE(VB_GENERAL,
- QString("MythNews: VideoURL %1").arg(cmdURL));
- }
- }
+ const NewsArticle article = *it;
- QString fileprefix = GetConfDir();
+ if (article.enclosure().isEmpty())
+ {
+ QString cmdUrl(article.articleURL());
+ cmdUrl.replace('\'', "%27");
- QDir dir(fileprefix);
- if (!dir.exists())
- dir.mkdir(fileprefix);
+ QString cmd = QString("%1 %2 '%3'")
+ .arg(browser)
+ .arg(zoom)
+ .arg(cmdUrl);
+ gContext->GetMainWindow()->AllowInput(false);
+ myth_system(cmd, MYTH_SYSTEM_DONT_BLOCK_PARENT);
+ gContext->GetMainWindow()->AllowInput(true);
+ return;
+ }
- fileprefix += "/MythNews";
+ QString cmdURL(article.enclosure());
- dir = QDir(fileprefix);
- if (!dir.exists())
- dir.mkdir(fileprefix);
+ // Handle special cases for media here
+ // YouTube: Fetch the mediaURL page and parse out the video URL
+ if (cmdURL.contains("youtube.com"))
+ {
+ cmdURL = QString(article.mediaURL());
+ QString mediaPage = HttpComms::getHttp(cmdURL);
+ if (!mediaPage.isEmpty())
+ {
+ // If this breaks in the future, we are building the URL
+ // to download a video. At this time, this requires
+ // the video_id and the t argument
+ // from the source HTML of the page
+ int playerPos = mediaPage.indexOf("swfArgs") + 7;
- QString sFilename(fileprefix + "/newstempfile");
+ int tArgStart = mediaPage.indexOf("\"t\": \"",
+ playerPos) + 6;
+ int tArgEnd = mediaPage.indexOf("\"", tArgStart);
+ QString tArgString = mediaPage.mid(tArgStart,
+ tArgEnd - tArgStart);
- if (getHttpFile(sFilename, cmdURL))
- {
- playVideo(sFilename);
- }
- }
- else {
- QString cmdUrl(article->articleURL());
- cmdUrl.replace('\'', "%27");
+ int vidStart = mediaPage.indexOf("\"video_id\": \"",
+ playerPos) + 13;
+ int vidEnd = mediaPage.indexOf("\"", vidStart);
+ QString vidString = mediaPage.mid(vidStart,
+ vidEnd - vidStart);
- QString cmd = QString("%1 %2 '%3'")
- .arg(browser)
- .arg(zoom)
- .arg(cmdUrl);
- gContext->GetMainWindow()->AllowInput(false);
- myth_system(cmd, MYTH_SYSTEM_DONT_BLOCK_PARENT);
- gContext->GetMainWindow()->AllowInput(true);
- }
+ cmdURL = QString("http://youtube.com/get_video.php"
+ "?video_id=%2&t=%1")
+ .arg(tArgString).arg(vidString);
+ VERBOSE(VB_GENERAL,
+ QString("MythNews: VideoURL %1").arg(cmdURL));
}
}
+
+ QString fileprefix = GetConfDir();
+
+ QDir dir(fileprefix);
+ if (!dir.exists())
+ dir.mkdir(fileprefix);
+
+ fileprefix += "/MythNews";
+
+ dir = QDir(fileprefix);
+ if (!dir.exists())
+ dir.mkdir(fileprefix);
+
+ QString sFilename(fileprefix + "/newstempfile");
+
+ if (getHttpFile(sFilename, cmdURL))
+ playVideo(sFilename);
}
void MythNews::ShowEditDialog(bool edit)
Index: mythnews/mythnews/httphandler.h
===================================================================
--- mythnews/mythnews/httphandler.h (revision 0)
+++ mythnews/mythnews/httphandler.h (revision 0)
@@ -0,0 +1,52 @@
+#ifndef _HTTP_HANDLER_H_
+#define _HTTP_HANDLER_H_
+
+// C++ headers
+#include <deque>
+using namespace std;
+
+// Qt headers
+#include <QMutex>
+#include <QUrl>
+
+typedef deque<QUrl> URLQueue;
+
+class QHttp;
+class QHttpResponseHeader;
+class HttpPool;
+
+class HttpHandler : public QObject
+{
+ Q_OBJECT
+ public:
+ HttpHandler(HttpPool *pool);
+ virtual void deleteLater(void) { TeardownAll(); QObject::deleteLater(); }
+
+ bool HasPendingRequests(void) const;
+ void AddURLRequest(const QUrl &url);
+ void RemoveURLRequest(const QUrl &url);
+
+ protected slots:
+ void Done(bool error);
+ void ResponseHeaderReceived(const QHttpResponseHeader &resp);
+ void RequestFinished(int id, bool error);
+ void RequestStarted(int id);
+ void StateChanged(int state);
+
+ private:
+ ~HttpHandler() { TeardownAll(); }
+ void TeardownAll();
+ void Get(const QUrl &url);
+
+ private:
+ mutable QMutex m_lock;
+ URLQueue m_urls;
+ QUrl m_cur_url;
+ uint m_cur_status_id;
+ int m_cur_get_id;
+ HttpPool *m_pool;
+ QHttp *m_qhttp;
+
+};
+
+#endif // _HTTP_HANDLER_H_
Index: mythnews/mythnews/mythnews.h
===================================================================
--- mythnews/mythnews/mythnews.h (revision 18874)
+++ mythnews/mythnews/mythnews.h (working copy)
@@ -69,6 +69,7 @@
MythUIButtonList *m_sitesList;
MythUIButtonList *m_articlesList;
+ QMap<MythUIButtonListItem*,NewsArticle> m_articles;
MythUIText *m_updatedText;
MythUIText *m_titleText;
Index: mythnews/mythnews/mythnews.pro
===================================================================
--- mythnews/mythnews/mythnews.pro (revision 18874)
+++ mythnews/mythnews/mythnews.pro (working copy)
@@ -1,6 +1,8 @@
include ( ../../mythconfig.mak )
include ( ../../settings.pro )
include ( ../../programs-libs.pro )
+
+QT += network sql xml
TEMPLATE = lib
CONFIG += plugin thread warn_on debug
@@ -21,7 +23,7 @@
SOURCES += main.cpp mythnews.cpp mythnewsconfig.cpp mythnewseditor.cpp
SOURCES += newsengine.cpp newsdbutil.cpp dbcheck.cpp
-#The following line was inserted by qt3to4
-QT += network sql xml qt3support
+HEADERS += httppool.h httphandler.h
+SOURCES += httppool.cpp httphandler.cpp
include ( ../../libs-targetfix.pro )