From 67758cb0925ada8089f3629b0e7ecb6886b1f3a3 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Wed, 14 Oct 2015 12:49:29 +0300 Subject: [PATCH] Fix coding style (Issue #2192). --- src/base/rss/rssarticle.cpp | 133 +++-- src/base/rss/rssarticle.h | 71 +-- src/base/rss/rssdownloadrule.cpp | 365 ++++++++---- src/base/rss/rssdownloadrule.h | 101 ++-- src/base/rss/rssdownloadrulelist.cpp | 187 +++--- src/base/rss/rssdownloadrulelist.h | 43 +- src/base/rss/rssfeed.cpp | 542 ++++++++--------- src/base/rss/rssfeed.h | 114 ++-- src/base/rss/rssfile.cpp | 20 +- src/base/rss/rssfile.h | 43 +- src/base/rss/rssfolder.cpp | 351 ++++++----- src/base/rss/rssfolder.h | 73 +-- src/base/rss/rssmanager.cpp | 171 +++--- src/base/rss/rssmanager.h | 48 +- src/base/rss/rssparser.cpp | 834 ++++++++++++++------------- src/base/rss/rssparser.h | 47 +- src/gui/rss/feedlistwidget.cpp | 4 +- 17 files changed, 1690 insertions(+), 1457 deletions(-) diff --git a/src/base/rss/rssarticle.cpp b/src/base/rss/rssarticle.cpp index 34ab247eb..585da24c7 100644 --- a/src/base/rss/rssarticle.cpp +++ b/src/base/rss/rssarticle.cpp @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez, Arnaud Demaiziere + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2010 Arnaud Demaiziere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -36,93 +37,107 @@ #include "rssarticle.h" // public constructor -RssArticle::RssArticle(RssFeed* parent, const QString& guid): - m_parent(parent), m_guid(guid), m_read(false) {} +RssArticle::RssArticle(RssFeed *parent, const QString &guid) + : m_parent(parent) + , m_guid(guid) + , m_read(false) +{ +} -bool RssArticle::hasAttachment() const { - return !m_torrentUrl.isEmpty(); +bool RssArticle::hasAttachment() const +{ + return !m_torrentUrl.isEmpty(); } -QVariantHash RssArticle::toHash() const { - QVariantHash item; - item["title"] = m_title; - item["id"] = m_guid; - item["torrent_url"] = m_torrentUrl; - item["news_link"] = m_link; - item["description"] = m_description; - item["date"] = m_date; - item["author"] = m_author; - item["read"] = m_read; - return item; +QVariantHash RssArticle::toHash() const +{ + QVariantHash item; + item["title"] = m_title; + item["id"] = m_guid; + item["torrent_url"] = m_torrentUrl; + item["news_link"] = m_link; + item["description"] = m_description; + item["date"] = m_date; + item["author"] = m_author; + item["read"] = m_read; + return item; } -RssArticlePtr hashToRssArticle(RssFeed* parent, const QVariantHash& h) { - const QString guid = h.value("id").toString(); - if (guid.isEmpty()) - return RssArticlePtr(); - - RssArticlePtr art(new RssArticle(parent, guid)); - art->m_title = h.value("title", "").toString(); - art->m_torrentUrl = h.value("torrent_url", "").toString(); - art->m_link = h.value("news_link", "").toString(); - art->m_description = h.value("description").toString(); - art->m_date = h.value("date").toDateTime(); - art->m_author = h.value("author").toString(); - art->m_read = h.value("read", false).toBool(); - - return art; +RssArticlePtr RssArticle::fromHash(RssFeed *parent, const QVariantHash &h) +{ + const QString guid = h.value("id").toString(); + if (guid.isEmpty()) + return RssArticlePtr(); + + RssArticlePtr art(new RssArticle(parent, guid)); + art->m_title = h.value("title", "").toString(); + art->m_torrentUrl = h.value("torrent_url", "").toString(); + art->m_link = h.value("news_link", "").toString(); + art->m_description = h.value("description").toString(); + art->m_date = h.value("date").toDateTime(); + art->m_author = h.value("author").toString(); + art->m_read = h.value("read", false).toBool(); + + return art; } -RssFeed* RssArticle::parent() const { - return m_parent; +RssFeed *RssArticle::parent() const +{ + return m_parent; } -const QString& RssArticle::author() const { - return m_author; +const QString &RssArticle::author() const +{ + return m_author; } -const QString& RssArticle::torrentUrl() const { - return m_torrentUrl; +const QString &RssArticle::torrentUrl() const +{ + return m_torrentUrl; } -const QString& RssArticle::link() const { - return m_link; +const QString &RssArticle::link() const +{ + return m_link; } QString RssArticle::description() const { - return m_description.isNull() ? "" : m_description; + return m_description.isNull() ? "" : m_description; } -const QDateTime& RssArticle::date() const { - return m_date; +const QDateTime &RssArticle::date() const +{ + return m_date; } -bool RssArticle::isRead() const { - return m_read; +bool RssArticle::isRead() const +{ + return m_read; } -void RssArticle::markAsRead() { - if (m_read) - return; +void RssArticle::markAsRead() +{ + if (m_read) return; - m_read = true; - m_parent->decrementUnreadCount(); - m_parent->markAsDirty(); - emit articleWasRead(); + m_read = true; + m_parent->decrementUnreadCount(); + m_parent->markAsDirty(); + emit articleWasRead(); } -const QString& RssArticle::guid() const +const QString &RssArticle::guid() const { - return m_guid; + return m_guid; } -const QString& RssArticle::title() const +const QString &RssArticle::title() const { - return m_title; + return m_title; } -void RssArticle::handleTorrentDownloadSuccess(const QString &url) { - if (url == m_torrentUrl) - markAsRead(); +void RssArticle::handleTorrentDownloadSuccess(const QString &url) +{ + if (url == m_torrentUrl) + markAsRead(); } diff --git a/src/base/rss/rssarticle.h b/src/base/rss/rssarticle.h index 7deeaf560..72bdac20c 100644 --- a/src/base/rss/rssarticle.h +++ b/src/base/rss/rssarticle.h @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez, Arnaud Demaiziere + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2010 Arnaud Demaiziere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -42,47 +43,47 @@ class RssArticle; typedef QSharedPointer RssArticlePtr; // Item of a rss stream, single information -class RssArticle : public QObject { - Q_OBJECT +class RssArticle: public QObject +{ + Q_OBJECT public: - RssArticle(RssFeed* parent, const QString& guid); - // Accessors - bool hasAttachment() const; - const QString& guid() const; - RssFeed* parent() const; - const QString& title() const; - const QString& author() const; - const QString& torrentUrl() const; - const QString& link() const; - QString description() const; - const QDateTime& date() const; - bool isRead() const; - // Setters - void markAsRead(); - // Serialization - QVariantHash toHash() const; + RssArticle(RssFeed *parent, const QString &guid); + + // Accessors + bool hasAttachment() const; + const QString &guid() const; + RssFeed *parent() const; + const QString &title() const; + const QString &author() const; + const QString &torrentUrl() const; + const QString &link() const; + QString description() const; + const QDateTime &date() const; + bool isRead() const; + // Setters + void markAsRead(); + + // Serialization + QVariantHash toHash() const; + static RssArticlePtr fromHash(RssFeed *parent, const QVariantHash &hash); signals: - void articleWasRead(); + void articleWasRead(); public slots: - void handleTorrentDownloadSuccess(const QString& url); - - friend RssArticlePtr hashToRssArticle(RssFeed* parent, const QVariantHash& hash); + void handleTorrentDownloadSuccess(const QString &url); private: - RssFeed* m_parent; - QString m_guid; - QString m_title; - QString m_torrentUrl; - QString m_link; - QString m_description; - QDateTime m_date; - QString m_author; - bool m_read; + RssFeed *m_parent; + QString m_guid; + QString m_title; + QString m_torrentUrl; + QString m_link; + QString m_description; + QDateTime m_date; + QString m_author; + bool m_read; }; -RssArticlePtr hashToRssArticle(RssFeed* parent, const QVariantHash& hash); - #endif // RSSARTICLE_H diff --git a/src/base/rss/rssdownloadrule.cpp b/src/base/rss/rssdownloadrule.cpp index 132166e06..25d4d4cd1 100644 --- a/src/base/rss/rssdownloadrule.cpp +++ b/src/base/rss/rssdownloadrule.cpp @@ -1,5 +1,5 @@ /* - * Bittorrent Client using Qt4 and libtorrent. + * Bittorrent Client using Qt and libtorrent. * Copyright (C) 2010 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -38,163 +38,272 @@ #include "rssarticle.h" #include "rssdownloadrule.h" -RssDownloadRule::RssDownloadRule(): m_enabled(false), m_useRegex(false), m_apstate(USE_GLOBAL) +RssDownloadRule::RssDownloadRule() + : m_enabled(false) + , m_useRegex(false) + , m_apstate(USE_GLOBAL) { } -bool RssDownloadRule::matches(const QString &article_title) const +bool RssDownloadRule::matches(const QString &articleTitle) const { - foreach (const QString& token, m_mustContain) { - if (!token.isEmpty()) { - QRegExp reg(token, Qt::CaseInsensitive, m_useRegex ? QRegExp::RegExp : QRegExp::Wildcard); - if (reg.indexIn(article_title) < 0) - return false; - } - } - qDebug("Checking not matching tokens"); - // Checking not matching - foreach (const QString& token, m_mustNotContain) { - if (!token.isEmpty()) { - QRegExp reg(token, Qt::CaseInsensitive, m_useRegex ? QRegExp::RegExp : QRegExp::Wildcard); - if (reg.indexIn(article_title) > -1) - return false; + foreach (const QString &token, m_mustContain) { + if (!token.isEmpty()) { + QRegExp reg(token, Qt::CaseInsensitive, m_useRegex ? QRegExp::RegExp : QRegExp::Wildcard); + if (reg.indexIn(articleTitle) < 0) + return false; + } } - } - if (!m_episodeFilter.isEmpty()) { - qDebug("Checking episode filter"); - QRegExp f("(^\\d{1,4})x(.*;$)"); - int pos = f.indexIn(m_episodeFilter); - if (pos < 0) - return false; - - QString s = f.cap(1); - QStringList eps = f.cap(2).split(";"); - QString expStr; - expStr += "s0?" + s + "[ -_\\.]?" + "e0?"; - - foreach (const QString& ep, eps) { - if (ep.isEmpty()) - continue; - - if (ep.indexOf('-') != -1) { // Range detected - QString partialPattern = "s0?" + s + "[ -_\\.]?" + "e(0?\\d{1,4})"; - QRegExp reg(partialPattern, Qt::CaseInsensitive); - - if (ep.endsWith('-')) { // Infinite range - int epOurs = ep.left(ep.size() - 1).toInt(); - - // Extract partial match from article and compare as digits - pos = reg.indexIn(article_title); - if (pos != -1) { - int epTheirs = reg.cap(1).toInt(); - if (epTheirs >= epOurs) - return true; - } + qDebug("Checking not matching tokens"); + // Checking not matching + foreach (const QString &token, m_mustNotContain) { + if (!token.isEmpty()) { + QRegExp reg(token, Qt::CaseInsensitive, m_useRegex ? QRegExp::RegExp : QRegExp::Wildcard); + if (reg.indexIn(articleTitle) > -1) + return false; } - else { // Normal range - QStringList range = ep.split('-'); - Q_ASSERT(range.size() == 2); - if (range.first().toInt() > range.last().toInt()) - continue; // Ignore this subrule completely - - int epOursFirst = range.first().toInt(); - int epOursLast = range.last().toInt(); - - // Extract partial match from article and compare as digits - pos = reg.indexIn(article_title); - if (pos != -1) { - int epTheirs = reg.cap(1).toInt(); - if (epOursFirst <= epTheirs && epOursLast >= epTheirs) - return true; - } + } + if (!m_episodeFilter.isEmpty()) { + qDebug("Checking episode filter"); + QRegExp f("(^\\d{1,4})x(.*;$)"); + int pos = f.indexIn(m_episodeFilter); + if (pos < 0) + return false; + + QString s = f.cap(1); + QStringList eps = f.cap(2).split(";"); + QString expStr; + expStr += "s0?" + s + "[ -_\\.]?" + "e0?"; + + foreach (const QString &ep, eps) { + if (ep.isEmpty()) + continue; + + if (ep.indexOf('-') != -1) { // Range detected + QString partialPattern = "s0?" + s + "[ -_\\.]?" + "e(0?\\d{1,4})"; + QRegExp reg(partialPattern, Qt::CaseInsensitive); + + if (ep.endsWith('-')) { // Infinite range + int epOurs = ep.left(ep.size() - 1).toInt(); + + // Extract partial match from article and compare as digits + pos = reg.indexIn(articleTitle); + if (pos != -1) { + int epTheirs = reg.cap(1).toInt(); + if (epTheirs >= epOurs) + return true; + } + } + else { // Normal range + QStringList range = ep.split('-'); + Q_ASSERT(range.size() == 2); + if (range.first().toInt() > range.last().toInt()) + continue; // Ignore this subrule completely + + int epOursFirst = range.first().toInt(); + int epOursLast = range.last().toInt(); + + // Extract partial match from article and compare as digits + pos = reg.indexIn(articleTitle); + if (pos != -1) { + int epTheirs = reg.cap(1).toInt(); + if (epOursFirst <= epTheirs && epOursLast >= epTheirs) + return true; + } + } + } + else { // Single number + QRegExp reg(expStr + ep + "\\D", Qt::CaseInsensitive); + if (reg.indexIn(articleTitle) != -1) + return true; + } } - } - else { // Single number - QRegExp reg(expStr + ep + "\\D", Qt::CaseInsensitive); - if (reg.indexIn(article_title) != -1) - return true; - } + return false; } - return false; - } - return true; + return true; } void RssDownloadRule::setMustContain(const QString &tokens) { - if (m_useRegex) - m_mustContain = QStringList() << tokens; - else - m_mustContain = tokens.split(" "); + if (m_useRegex) + m_mustContain = QStringList() << tokens; + else + m_mustContain = tokens.split(" "); } void RssDownloadRule::setMustNotContain(const QString &tokens) { - if (m_useRegex) - m_mustNotContain = QStringList() << tokens; - else - m_mustNotContain = tokens.split("|"); + if (m_useRegex) + m_mustNotContain = QStringList() << tokens; + else + m_mustNotContain = tokens.split("|"); +} + +QStringList RssDownloadRule::rssFeeds() const +{ + return m_rssFeeds; } -RssDownloadRulePtr RssDownloadRule::fromVariantHash(const QVariantHash &rule_hash) +void RssDownloadRule::setRssFeeds(const QStringList &rssFeeds) { - RssDownloadRulePtr rule(new RssDownloadRule); - rule->setName(rule_hash.value("name").toString()); - rule->setUseRegex(rule_hash.value("use_regex", false).toBool()); - rule->setMustContain(rule_hash.value("must_contain").toString()); - rule->setMustNotContain(rule_hash.value("must_not_contain").toString()); - rule->setEpisodeFilter(rule_hash.value("episode_filter").toString()); - rule->setRssFeeds(rule_hash.value("affected_feeds").toStringList()); - rule->setEnabled(rule_hash.value("enabled", false).toBool()); - rule->setSavePath(rule_hash.value("save_path").toString()); - rule->setLabel(rule_hash.value("label_assigned").toString()); - rule->setAddPaused(AddPausedState(rule_hash.value("add_paused").toUInt())); - rule->setLastMatch(rule_hash.value("last_match").toDateTime()); - rule->setIgnoreDays(rule_hash.value("ignore_days").toInt()); - return rule; + m_rssFeeds = rssFeeds; +} + +QString RssDownloadRule::name() const +{ + return m_name; +} + +void RssDownloadRule::setName(const QString &name) +{ + m_name = name; +} + +QString RssDownloadRule::savePath() const +{ + return m_savePath; +} + +RssDownloadRulePtr RssDownloadRule::fromVariantHash(const QVariantHash &ruleHash) +{ + RssDownloadRulePtr rule(new RssDownloadRule); + rule->setName(ruleHash.value("name").toString()); + rule->setUseRegex(ruleHash.value("use_regex", false).toBool()); + rule->setMustContain(ruleHash.value("must_contain").toString()); + rule->setMustNotContain(ruleHash.value("must_not_contain").toString()); + rule->setEpisodeFilter(ruleHash.value("episode_filter").toString()); + rule->setRssFeeds(ruleHash.value("affected_feeds").toStringList()); + rule->setEnabled(ruleHash.value("enabled", false).toBool()); + rule->setSavePath(ruleHash.value("save_path").toString()); + rule->setLabel(ruleHash.value("label_assigned").toString()); + rule->setAddPaused(AddPausedState(ruleHash.value("add_paused").toUInt())); + rule->setLastMatch(ruleHash.value("last_match").toDateTime()); + rule->setIgnoreDays(ruleHash.value("ignore_days").toInt()); + return rule; } QVariantHash RssDownloadRule::toVariantHash() const { - QVariantHash hash; - hash["name"] = m_name; - hash["must_contain"] = m_mustContain.join(" "); - hash["must_not_contain"] = m_mustNotContain.join("|"); - hash["save_path"] = m_savePath; - hash["affected_feeds"] = m_rssFeeds; - hash["enabled"] = m_enabled; - hash["label_assigned"] = m_label; - hash["use_regex"] = m_useRegex; - hash["add_paused"] = m_apstate; - hash["episode_filter"] = m_episodeFilter; - hash["last_match"] = m_lastMatch; - hash["ignore_days"] = m_ignoreDays; - return hash; + QVariantHash hash; + hash["name"] = m_name; + hash["must_contain"] = m_mustContain.join(" "); + hash["must_not_contain"] = m_mustNotContain.join("|"); + hash["save_path"] = m_savePath; + hash["affected_feeds"] = m_rssFeeds; + hash["enabled"] = m_enabled; + hash["label_assigned"] = m_label; + hash["use_regex"] = m_useRegex; + hash["add_paused"] = m_apstate; + hash["episode_filter"] = m_episodeFilter; + hash["last_match"] = m_lastMatch; + hash["ignore_days"] = m_ignoreDays; + return hash; +} + +bool RssDownloadRule::operator==(const RssDownloadRule &other) const +{ + return m_name == other.name(); +} + +void RssDownloadRule::setSavePath(const QString &savePath) +{ + if (!savePath.isEmpty() && (QDir(savePath) != QDir(Preferences::instance()->getSavePath()))) + m_savePath = Utils::Fs::fromNativePath(savePath); + else + m_savePath = QString(); +} + +RssDownloadRule::AddPausedState RssDownloadRule::addPaused() const +{ + return m_apstate; +} + +void RssDownloadRule::setAddPaused(const RssDownloadRule::AddPausedState &aps) +{ + m_apstate = aps; +} + +QString RssDownloadRule::label() const +{ + return m_label; +} + +void RssDownloadRule::setLabel(const QString &label) +{ + m_label = label; +} + +bool RssDownloadRule::isEnabled() const +{ + return m_enabled; } -bool RssDownloadRule::operator==(const RssDownloadRule &other) const { - return m_name == other.name(); +void RssDownloadRule::setEnabled(bool enable) +{ + m_enabled = enable; +} + +void RssDownloadRule::setLastMatch(const QDateTime &d) +{ + m_lastMatch = d; +} + +QDateTime RssDownloadRule::lastMatch() const +{ + return m_lastMatch; } -void RssDownloadRule::setSavePath(const QString &save_path) +void RssDownloadRule::setIgnoreDays(int d) { - if (!save_path.isEmpty() && QDir(save_path) != QDir(Preferences::instance()->getSavePath())) - m_savePath = Utils::Fs::fromNativePath(save_path); - else - m_savePath = QString(); + m_ignoreDays = d; } -QStringList RssDownloadRule::findMatchingArticles(const RssFeedPtr& feed) const +int RssDownloadRule::ignoreDays() const { - QStringList ret; - const RssArticleHash& feed_articles = feed->articleHash(); + return m_ignoreDays; +} - RssArticleHash::ConstIterator artIt = feed_articles.begin(); - RssArticleHash::ConstIterator artItend = feed_articles.end(); - for ( ; artIt != artItend ; ++artIt) { - const QString title = artIt.value()->title(); - if (matches(title)) - ret << title; - } - return ret; +QString RssDownloadRule::mustContain() const +{ + return m_mustContain.join(" "); +} + +QString RssDownloadRule::mustNotContain() const +{ + return m_mustNotContain.join("|"); +} + +bool RssDownloadRule::useRegex() const +{ + return m_useRegex; +} + +void RssDownloadRule::setUseRegex(bool enabled) +{ + m_useRegex = enabled; +} + +QString RssDownloadRule::episodeFilter() const +{ + return m_episodeFilter; +} + +void RssDownloadRule::setEpisodeFilter(const QString &e) +{ + m_episodeFilter = e; +} + +QStringList RssDownloadRule::findMatchingArticles(const RssFeedPtr &feed) const +{ + QStringList ret; + const RssArticleHash &feedArticles = feed->articleHash(); + + RssArticleHash::ConstIterator artIt = feedArticles.begin(); + RssArticleHash::ConstIterator artItend = feedArticles.end(); + for ( ; artIt != artItend ; ++artIt) { + const QString title = artIt.value()->title(); + if (matches(title)) + ret << title; + } + return ret; } diff --git a/src/base/rss/rssdownloadrule.h b/src/base/rss/rssdownloadrule.h index c76bd3187..0bfc0616f 100644 --- a/src/base/rss/rssdownloadrule.h +++ b/src/base/rss/rssdownloadrule.h @@ -1,5 +1,5 @@ /* - * Bittorrent Client using Qt4 and libtorrent. + * Bittorrent Client using Qt and libtorrent. * Copyright (C) 2010 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -44,59 +44,60 @@ typedef QSharedPointer RssDownloadRulePtr; class RssDownloadRule { - public: - enum AddPausedState { - USE_GLOBAL = 0, - ALWAYS_PAUSED, - NEVER_PAUSED - }; + enum AddPausedState + { + USE_GLOBAL = 0, + ALWAYS_PAUSED, + NEVER_PAUSED + }; + + RssDownloadRule(); - explicit RssDownloadRule(); - static RssDownloadRulePtr fromVariantHash(const QVariantHash &rule_hash); - QVariantHash toVariantHash() const; - bool matches(const QString &article_title) const; - void setMustContain(const QString &tokens); - void setMustNotContain(const QString &tokens); - inline QStringList rssFeeds() const { return m_rssFeeds; } - inline void setRssFeeds(const QStringList& rss_feeds) { m_rssFeeds = rss_feeds; } - inline QString name() const { return m_name; } - inline void setName(const QString &name) { m_name = name; } - inline QString savePath() const { return m_savePath; } - void setSavePath(const QString &save_path); - inline AddPausedState addPaused() const { return m_apstate; } - inline void setAddPaused(const AddPausedState &aps) { m_apstate = aps; } - inline QString label() const { return m_label; } - inline void setLabel(const QString &_label) { m_label = _label; } - inline bool isEnabled() const { return m_enabled; } - inline void setEnabled(bool enable) { m_enabled = enable; } - inline void setLastMatch(const QDateTime& d) { m_lastMatch = d; } - inline QDateTime lastMatch() const { return m_lastMatch; } - inline void setIgnoreDays(int d) { m_ignoreDays = d; } - inline int ignoreDays() const { return m_ignoreDays; } - inline QString mustContain() const { return m_mustContain.join(" "); } - inline QString mustNotContain() const { return m_mustNotContain.join("|"); } - inline bool useRegex() const { return m_useRegex; } - inline void setUseRegex(bool enabled) { m_useRegex = enabled; } - inline QString episodeFilter() const { return m_episodeFilter; } - inline void setEpisodeFilter(const QString& e) { m_episodeFilter = e; } - QStringList findMatchingArticles(const RssFeedPtr& feed) const; - // Operators - bool operator==(const RssDownloadRule &other) const; + static RssDownloadRulePtr fromVariantHash(const QVariantHash &ruleHash); + QVariantHash toVariantHash() const; + bool matches(const QString &articleTitle) const; + void setMustContain(const QString &tokens); + void setMustNotContain(const QString &tokens); + QStringList rssFeeds() const; + void setRssFeeds(const QStringList &rssFeeds); + QString name() const; + void setName(const QString &name); + QString savePath() const; + void setSavePath(const QString &savePath); + AddPausedState addPaused() const; + void setAddPaused(const AddPausedState &aps); + QString label() const; + void setLabel(const QString &label); + bool isEnabled() const; + void setEnabled(bool enable); + void setLastMatch(const QDateTime &d); + QDateTime lastMatch() const; + void setIgnoreDays(int d); + int ignoreDays() const; + QString mustContain() const; + QString mustNotContain() const; + bool useRegex() const; + void setUseRegex(bool enabled); + QString episodeFilter() const; + void setEpisodeFilter(const QString &e); + QStringList findMatchingArticles(const RssFeedPtr &feed) const; + // Operators + bool operator==(const RssDownloadRule &other) const; private: - QString m_name; - QStringList m_mustContain; - QStringList m_mustNotContain; - QString m_episodeFilter; - QString m_savePath; - QString m_label; - bool m_enabled; - QStringList m_rssFeeds; - bool m_useRegex; - AddPausedState m_apstate; - QDateTime m_lastMatch; - int m_ignoreDays; + QString m_name; + QStringList m_mustContain; + QStringList m_mustNotContain; + QString m_episodeFilter; + QString m_savePath; + QString m_label; + bool m_enabled; + QStringList m_rssFeeds; + bool m_useRegex; + AddPausedState m_apstate; + QDateTime m_lastMatch; + int m_ignoreDays; }; #endif // RSSDOWNLOADRULE_H diff --git a/src/base/rss/rssdownloadrulelist.cpp b/src/base/rss/rssdownloadrulelist.cpp index c1d450769..4f3e71bc4 100644 --- a/src/base/rss/rssdownloadrulelist.cpp +++ b/src/base/rss/rssdownloadrulelist.cpp @@ -1,5 +1,5 @@ /* - * Bittorrent Client using Qt4 and libtorrent. + * Bittorrent Client using Qt and libtorrent. * Copyright (C) 2010 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -38,135 +38,146 @@ RssDownloadRuleList::RssDownloadRuleList() { - loadRulesFromStorage(); + loadRulesFromStorage(); } -RssDownloadRulePtr RssDownloadRuleList::findMatchingRule(const QString &feed_url, const QString &article_title) const +RssDownloadRulePtr RssDownloadRuleList::findMatchingRule(const QString &feedUrl, const QString &articleTitle) const { - Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled()); - QStringList rule_names = m_feedRules.value(feed_url); - foreach (const QString &rule_name, rule_names) { - RssDownloadRulePtr rule = m_rules[rule_name]; - if (rule->isEnabled() && rule->matches(article_title)) return rule; - } - return RssDownloadRulePtr(); + Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled()); + QStringList ruleNames = m_feedRules.value(feedUrl); + foreach (const QString &rule_name, ruleNames) { + RssDownloadRulePtr rule = m_rules[rule_name]; + if (rule->isEnabled() && rule->matches(articleTitle)) return rule; + } + return RssDownloadRulePtr(); } -void RssDownloadRuleList::replace(RssDownloadRuleList *other) { - m_rules.clear(); - m_feedRules.clear(); - foreach (const QString& name, other->ruleNames()) { - saveRule(other->getRule(name)); - } +void RssDownloadRuleList::replace(RssDownloadRuleList *other) +{ + m_rules.clear(); + m_feedRules.clear(); + foreach (const QString &name, other->ruleNames()) { + saveRule(other->getRule(name)); + } } void RssDownloadRuleList::saveRulesToStorage() { - QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); - qBTRSS.setValue("download_rules", toVariantHash()); + QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); + qBTRSS.setValue("download_rules", toVariantHash()); } void RssDownloadRuleList::loadRulesFromStorage() { - QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); - loadRulesFromVariantHash(qBTRSS.value("download_rules").toHash()); + QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); + loadRulesFromVariantHash(qBTRSS.value("download_rules").toHash()); } QVariantHash RssDownloadRuleList::toVariantHash() const { - QVariantHash ret; - foreach (const RssDownloadRulePtr &rule, m_rules.values()) { - ret.insert(rule->name(), rule->toVariantHash()); - } - return ret; + QVariantHash ret; + foreach (const RssDownloadRulePtr &rule, m_rules.values()) { + ret.insert(rule->name(), rule->toVariantHash()); + } + return ret; } void RssDownloadRuleList::loadRulesFromVariantHash(const QVariantHash &h) { - QVariantHash::ConstIterator it = h.begin(); - QVariantHash::ConstIterator itend = h.end(); - for ( ; it != itend; ++it) { - RssDownloadRulePtr rule = RssDownloadRule::fromVariantHash(it.value().toHash()); - if (rule && !rule->name().isEmpty()) - saveRule(rule); - } + QVariantHash::ConstIterator it = h.begin(); + QVariantHash::ConstIterator itend = h.end(); + for ( ; it != itend; ++it) { + RssDownloadRulePtr rule = RssDownloadRule::fromVariantHash(it.value().toHash()); + if (rule && !rule->name().isEmpty()) + saveRule(rule); + } } void RssDownloadRuleList::saveRule(const RssDownloadRulePtr &rule) { - qDebug() << Q_FUNC_INFO << rule->name(); - Q_ASSERT(rule); - if (m_rules.contains(rule->name())) { - qDebug("This is an update, removing old rule first"); - removeRule(rule->name()); - } - m_rules.insert(rule->name(), rule); - // Update feedRules hashtable - foreach (const QString &feed_url, rule->rssFeeds()) { - m_feedRules[feed_url].append(rule->name()); - } - qDebug() << Q_FUNC_INFO << "EXIT"; + qDebug() << Q_FUNC_INFO << rule->name(); + Q_ASSERT(rule); + if (m_rules.contains(rule->name())) { + qDebug("This is an update, removing old rule first"); + removeRule(rule->name()); + } + m_rules.insert(rule->name(), rule); + // Update feedRules hashtable + foreach (const QString &feedUrl, rule->rssFeeds()) { + m_feedRules[feedUrl].append(rule->name()); + } + qDebug() << Q_FUNC_INFO << "EXIT"; } void RssDownloadRuleList::removeRule(const QString &name) { - qDebug() << Q_FUNC_INFO << name; - if (!m_rules.contains(name)) return; - RssDownloadRulePtr rule = m_rules.take(name); - // Update feedRules hashtable - foreach (const QString &feed_url, rule->rssFeeds()) { - m_feedRules[feed_url].removeOne(rule->name()); - } + qDebug() << Q_FUNC_INFO << name; + if (!m_rules.contains(name)) return; + RssDownloadRulePtr rule = m_rules.take(name); + // Update feedRules hashtable + foreach (const QString &feedUrl, rule->rssFeeds()) { + m_feedRules[feedUrl].removeOne(rule->name()); + } } -void RssDownloadRuleList::renameRule(const QString &old_name, const QString &new_name) +void RssDownloadRuleList::renameRule(const QString &oldName, const QString &newName) { - if (!m_rules.contains(old_name)) return; - RssDownloadRulePtr rule = m_rules.take(old_name); - rule->setName(new_name); - m_rules.insert(new_name, rule); - // Update feedRules hashtable - foreach (const QString &feed_url, rule->rssFeeds()) { - m_feedRules[feed_url].replace(m_feedRules[feed_url].indexOf(old_name), new_name); - } + if (!m_rules.contains(oldName)) return; + + RssDownloadRulePtr rule = m_rules.take(oldName); + rule->setName(newName); + m_rules.insert(newName, rule); + // Update feedRules hashtable + foreach (const QString &feedUrl, rule->rssFeeds()) { + m_feedRules[feedUrl].replace(m_feedRules[feedUrl].indexOf(oldName), newName); + } } RssDownloadRulePtr RssDownloadRuleList::getRule(const QString &name) const { - return m_rules.value(name); + return m_rules.value(name); } -bool RssDownloadRuleList::serialize(const QString& path) +QStringList RssDownloadRuleList::ruleNames() const { - QFile f(path); - if (f.open(QIODevice::WriteOnly)) { - QDataStream out(&f); - out.setVersion(QDataStream::Qt_4_5); - out << toVariantHash(); - f.close(); - return true; - } else { - return false; - } + return m_rules.keys(); } -bool RssDownloadRuleList::unserialize(const QString &path) +bool RssDownloadRuleList::isEmpty() const +{ + return m_rules.isEmpty(); +} + +bool RssDownloadRuleList::serialize(const QString &path) { - QFile f(path); - if (f.open(QIODevice::ReadOnly)) { - QDataStream in(&f); - in.setVersion(QDataStream::Qt_4_5); - QVariantHash tmp; - in >> tmp; - f.close(); - if (tmp.isEmpty()) - return false; - qDebug("Processing was successful!"); - loadRulesFromVariantHash(tmp); - return true; - } else { - qDebug("Error: could not open file at %s", qPrintable(path)); + QFile f(path); + if (f.open(QIODevice::WriteOnly)) { + QDataStream out(&f); + out.setVersion(QDataStream::Qt_4_5); + out << toVariantHash(); + f.close(); + return true; + } + return false; - } } +bool RssDownloadRuleList::unserialize(const QString &path) +{ + QFile f(path); + if (f.open(QIODevice::ReadOnly)) { + QDataStream in(&f); + in.setVersion(QDataStream::Qt_4_5); + QVariantHash tmp; + in >> tmp; + f.close(); + if (tmp.isEmpty()) + return false; + qDebug("Processing was successful!"); + loadRulesFromVariantHash(tmp); + return true; + } else { + qDebug("Error: could not open file at %s", qPrintable(path)); + return false; + } +} diff --git a/src/base/rss/rssdownloadrulelist.h b/src/base/rss/rssdownloadrulelist.h index 4a20c4744..4afc8c3e4 100644 --- a/src/base/rss/rssdownloadrulelist.h +++ b/src/base/rss/rssdownloadrulelist.h @@ -1,5 +1,5 @@ /* - * Bittorrent Client using Qt4 and libtorrent. + * Bittorrent Client using Qt and libtorrent. * Copyright (C) 2010 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -34,36 +34,37 @@ #include #include #include + #include "rssdownloadrule.h" class RssDownloadRuleList { - Q_DISABLE_COPY(RssDownloadRuleList) + Q_DISABLE_COPY(RssDownloadRuleList) public: - RssDownloadRuleList(); - RssDownloadRulePtr findMatchingRule(const QString &feed_url, const QString &article_title) const; - // Operators - void saveRule(const RssDownloadRulePtr &rule); - void removeRule(const QString &name); - void renameRule(const QString &old_name, const QString &new_name); - RssDownloadRulePtr getRule(const QString &name) const; - inline QStringList ruleNames() const { return m_rules.keys(); } - inline bool isEmpty() const { return m_rules.isEmpty(); } - void saveRulesToStorage(); - bool serialize(const QString& path); - bool unserialize(const QString& path); - void replace(RssDownloadRuleList* other); + RssDownloadRuleList(); -private: - void loadRulesFromStorage(); - void loadRulesFromVariantHash(const QVariantHash& l); - QVariantHash toVariantHash() const; + RssDownloadRulePtr findMatchingRule(const QString &feedUrl, const QString &articleTitle) const; + // Operators + void saveRule(const RssDownloadRulePtr &rule); + void removeRule(const QString &name); + void renameRule(const QString &oldName, const QString &newName); + RssDownloadRulePtr getRule(const QString &name) const; + QStringList ruleNames() const; + bool isEmpty() const; + void saveRulesToStorage(); + bool serialize(const QString &path); + bool unserialize(const QString &path); + void replace(RssDownloadRuleList *other); private: - QHash m_rules; - QHash m_feedRules; + void loadRulesFromStorage(); + void loadRulesFromVariantHash(const QVariantHash &l); + QVariantHash toVariantHash() const; +private: + QHash m_rules; + QHash m_feedRules; }; #endif // RSSDOWNLOADFILTERLIST_H diff --git a/src/base/rss/rssfeed.cpp b/src/base/rss/rssfeed.cpp index 72bcb8993..f52ccc1c4 100644 --- a/src/base/rss/rssfeed.cpp +++ b/src/base/rss/rssfeed.cpp @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez, Arnaud Demaiziere + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2010 Arnaud Demaiziere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -30,15 +31,15 @@ #include -#include "base/bittorrent/session.h" -#include "base/bittorrent/magneturi.h" #include "base/preferences.h" #include "base/qinisettings.h" +#include "base/logger.h" +#include "base/bittorrent/session.h" +#include "base/bittorrent/magneturi.h" #include "base/utils/misc.h" +#include "base/utils/fs.h" #include "base/net/downloadmanager.h" #include "base/net/downloadhandler.h" -#include "base/utils/fs.h" -#include "base/logger.h" #include "rssdownloadrulelist.h" #include "rssarticle.h" #include "rssparser.h" @@ -46,404 +47,419 @@ #include "rssmanager.h" #include "rssfeed.h" -bool rssArticleDateRecentThan(const RssArticlePtr& left, const RssArticlePtr& right) +bool rssArticleDateRecentThan(const RssArticlePtr &left, const RssArticlePtr &right) { - return left->date() > right->date(); + return left->date() > right->date(); } -RssFeed::RssFeed(RssManager* manager, RssFolder* parent, const QString& url): - m_manager(manager), - m_parent(parent), - m_url (QUrl::fromEncoded(url.toUtf8()).toString()), - m_icon(":/icons/oxygen/application-rss+xml.png"), - m_unreadCount(0), - m_dirty(false), - m_inErrorState(false), - m_loading(false) +RssFeed::RssFeed(RssManager *manager, RssFolder *parent, const QString &url) + : m_manager(manager) + , m_parent(parent) + , m_url (QUrl::fromEncoded(url.toUtf8()).toString()) + , m_icon(":/icons/oxygen/application-rss+xml.png") + , m_unreadCount(0) + , m_dirty(false) + , m_inErrorState(false) + , m_loading(false) { - qDebug() << Q_FUNC_INFO << m_url; - // Listen for new RSS downloads - connect(manager->rssParser(), SIGNAL(feedTitle(QString,QString)), SLOT(handleFeedTitle(QString,QString))); - connect(manager->rssParser(), SIGNAL(newArticle(QString,QVariantHash)), SLOT(handleNewArticle(QString,QVariantHash))); - connect(manager->rssParser(), SIGNAL(feedParsingFinished(QString,QString)), SLOT(handleFeedParsingFinished(QString,QString))); + qDebug() << Q_FUNC_INFO << m_url; + // Listen for new RSS downloads + connect(manager->rssParser(), SIGNAL(feedTitle(QString,QString)), SLOT(handleFeedTitle(QString,QString))); + connect(manager->rssParser(), SIGNAL(newArticle(QString,QVariantHash)), SLOT(handleNewArticle(QString,QVariantHash))); + connect(manager->rssParser(), SIGNAL(feedParsingFinished(QString,QString)), SLOT(handleFeedParsingFinished(QString,QString))); - // Download the RSS Feed icon - Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(iconUrl(), true); - connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFinishedDownload(QString, QString))); - connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString))); - m_iconUrl = handler->url(); + // Download the RSS Feed icon + Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(iconUrl(), true); + connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFinishedDownload(QString, QString))); + connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString))); + m_iconUrl = handler->url(); - // Load old RSS articles - loadItemsFromDisk(); + // Load old RSS articles + loadItemsFromDisk(); } RssFeed::~RssFeed() { - if (!m_icon.startsWith(":/") && QFile::exists(m_icon)) - Utils::Fs::forceRemove(m_icon); + if (!m_icon.startsWith(":/") && QFile::exists(m_icon)) + Utils::Fs::forceRemove(m_icon); +} + +RssFolder *RssFeed::parent() const +{ + return m_parent; +} + +void RssFeed::setParent(RssFolder *parent) +{ + m_parent = parent; } void RssFeed::saveItemsToDisk() { - qDebug() << Q_FUNC_INFO << m_url; - if (!m_dirty) - return; - markAsDirty(false); + qDebug() << Q_FUNC_INFO << m_url; + if (!m_dirty) return; + + markAsDirty(false); - QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); - QVariantList old_items; + QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); + QVariantList oldItems; - RssArticleHash::ConstIterator it = m_articles.begin(); - RssArticleHash::ConstIterator itend = m_articles.end(); - for ( ; it != itend; ++it) { - old_items << it.value()->toHash(); - } - qDebug("Saving %d old items for feed %s", old_items.size(), qPrintable(displayName())); - QHash all_old_items = qBTRSS.value("old_items", QHash()).toHash(); - all_old_items[m_url] = old_items; - qBTRSS.setValue("old_items", all_old_items); + RssArticleHash::ConstIterator it = m_articles.begin(); + RssArticleHash::ConstIterator itend = m_articles.end(); + for ( ; it != itend; ++it) { + oldItems << it.value()->toHash(); + } + qDebug("Saving %d old items for feed %s", oldItems.size(), qPrintable(displayName())); + QHash allOldItems = qBTRSS.value("old_items", QHash()).toHash(); + allOldItems[m_url] = oldItems; + qBTRSS.setValue("old_items", allOldItems); } void RssFeed::loadItemsFromDisk() { - QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); - QHash all_old_items = qBTRSS.value("old_items", QHash()).toHash(); - const QVariantList old_items = all_old_items.value(m_url, QVariantList()).toList(); - qDebug("Loading %d old items for feed %s", old_items.size(), qPrintable(displayName())); - - foreach (const QVariant& var_it, old_items) { - QVariantHash item = var_it.toHash(); - RssArticlePtr rss_item = hashToRssArticle(this, item); - if (rss_item) - addArticle(rss_item); - } -} - -void RssFeed::addArticle(const RssArticlePtr& article) { - int max_articles = Preferences::instance()->getRSSMaxArticlesPerFeed(); - - if (!m_articles.contains(article->guid())) { - markAsDirty(); - - // Update unreadCount - if (!article->isRead()) - ++m_unreadCount; - // Insert in hash table - m_articles[article->guid()] = article; - // Insertion sort - RssArticleList::Iterator lowerBound = qLowerBound(m_articlesByDate.begin(), m_articlesByDate.end(), article, rssArticleDateRecentThan); - m_articlesByDate.insert(lowerBound, article); - int lbIndex = m_articlesByDate.indexOf(article); - if (m_articlesByDate.size() > max_articles) { - RssArticlePtr oldestArticle = m_articlesByDate.takeLast(); - m_articles.remove(oldestArticle->guid()); - // Update unreadCount - if (!oldestArticle->isRead()) - --m_unreadCount; + QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); + QHash allOldItems = qBTRSS.value("old_items", QHash()).toHash(); + const QVariantList oldItems = allOldItems.value(m_url, QVariantList()).toList(); + qDebug("Loading %d old items for feed %s", oldItems.size(), qPrintable(displayName())); + + foreach (const QVariant &var_it, oldItems) { + QVariantHash item = var_it.toHash(); + RssArticlePtr rssItem = RssArticle::fromHash(this, item); + if (rssItem) + addArticle(rssItem); } +} - // Check if article was inserted at the end of the list and will break max_articles limit - if (Preferences::instance()->isRssDownloadingEnabled()) { - if (lbIndex < max_articles && !article->isRead()) - downloadArticleTorrentIfMatching(m_manager->downloadRules(), article); +void RssFeed::addArticle(const RssArticlePtr &article) +{ + int maxArticles = Preferences::instance()->getRSSMaxArticlesPerFeed(); + + if (!m_articles.contains(article->guid())) { + markAsDirty(); + + // Update unreadCount + if (!article->isRead()) + ++m_unreadCount; + // Insert in hash table + m_articles[article->guid()] = article; + // Insertion sort + RssArticleList::Iterator lowerBound = qLowerBound(m_articlesByDate.begin(), m_articlesByDate.end(), article, rssArticleDateRecentThan); + m_articlesByDate.insert(lowerBound, article); + int lbIndex = m_articlesByDate.indexOf(article); + if (m_articlesByDate.size() > maxArticles) { + RssArticlePtr oldestArticle = m_articlesByDate.takeLast(); + m_articles.remove(oldestArticle->guid()); + // Update unreadCount + if (!oldestArticle->isRead()) + --m_unreadCount; + } + + // Check if article was inserted at the end of the list and will break max_articles limit + if (Preferences::instance()->isRssDownloadingEnabled()) { + if ((lbIndex < maxArticles) && !article->isRead()) + downloadArticleTorrentIfMatching(m_manager->downloadRules(), article); + } } - } - else { - // m_articles.contains(article->guid()) - // Try to download skipped articles - if (Preferences::instance()->isRssDownloadingEnabled()) { - RssArticlePtr skipped = m_articles.value(article->guid(), RssArticlePtr()); - if (skipped) { - if (!skipped->isRead()) - downloadArticleTorrentIfMatching(m_manager->downloadRules(), skipped); - } + else { + // m_articles.contains(article->guid()) + // Try to download skipped articles + if (Preferences::instance()->isRssDownloadingEnabled()) { + RssArticlePtr skipped = m_articles.value(article->guid(), RssArticlePtr()); + if (skipped) { + if (!skipped->isRead()) + downloadArticleTorrentIfMatching(m_manager->downloadRules(), skipped); + } + } } - } } bool RssFeed::refresh() { - if (m_loading) { - qWarning() << Q_FUNC_INFO << "Feed" << displayName() << "is already being refreshed, ignoring request"; - return false; - } - m_loading = true; - // Download the RSS again - Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_url, true); - connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFinishedDownload(QString, QString))); - connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString))); - m_url = handler->url(); // sync URL encoding - return true; + if (m_loading) { + qWarning() << Q_FUNC_INFO << "Feed" << displayName() << "is already being refreshed, ignoring request"; + return false; + } + m_loading = true; + // Download the RSS again + Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(m_url, true); + connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(handleFinishedDownload(QString, QString))); + connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString))); + m_url = handler->url(); // sync URL encoding + return true; +} + +QString RssFeed::id() const +{ + return m_url; } void RssFeed::removeAllSettings() { - qDebug() << "Removing all settings / history for feed: " << m_url; - QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); - QVariantHash feeds_w_downloader = qBTRSS.value("downloader_on", QVariantHash()).toHash(); - if (feeds_w_downloader.contains(m_url)) { - feeds_w_downloader.remove(m_url); - qBTRSS.setValue("downloader_on", feeds_w_downloader); - } - QVariantHash all_feeds_filters = qBTRSS.value("feed_filters", QVariantHash()).toHash(); - if (all_feeds_filters.contains(m_url)) { - all_feeds_filters.remove(m_url); - qBTRSS.setValue("feed_filters", all_feeds_filters); - } - QVariantHash all_old_items = qBTRSS.value("old_items", QVariantHash()).toHash(); - if (all_old_items.contains(m_url)) { - all_old_items.remove(m_url); - qBTRSS.setValue("old_items", all_old_items); - } + qDebug() << "Removing all settings / history for feed: " << m_url; + QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); + QVariantHash feedsWDownloader = qBTRSS.value("downloader_on", QVariantHash()).toHash(); + if (feedsWDownloader.contains(m_url)) { + feedsWDownloader.remove(m_url); + qBTRSS.setValue("downloader_on", feedsWDownloader); + } + QVariantHash allFeedsFilters = qBTRSS.value("feed_filters", QVariantHash()).toHash(); + if (allFeedsFilters.contains(m_url)) { + allFeedsFilters.remove(m_url); + qBTRSS.setValue("feed_filters", allFeedsFilters); + } + QVariantHash allOldItems = qBTRSS.value("old_items", QVariantHash()).toHash(); + if (allOldItems.contains(m_url)) { + allOldItems.remove(m_url); + qBTRSS.setValue("old_items", allOldItems); + } } bool RssFeed::isLoading() const { - return m_loading; + return m_loading; } QString RssFeed::title() const { - return m_title; + return m_title; } -void RssFeed::rename(const QString &new_name) +void RssFeed::rename(const QString &newName) { - qDebug() << "Renaming stream to" << new_name; - m_alias = new_name; + qDebug() << "Renaming stream to" << newName; + m_alias = newName; } // Return the alias if the stream has one, the url if it has no alias QString RssFeed::displayName() const { - if (!m_alias.isEmpty()) - return m_alias; - if (!m_title.isEmpty()) - return m_title; - return m_url; + if (!m_alias.isEmpty()) + return m_alias; + if (!m_title.isEmpty()) + return m_title; + return m_url; } QString RssFeed::url() const { - return m_url; + return m_url; } QString RssFeed::iconPath() const { - if (m_inErrorState) - return QLatin1String(":/icons/oxygen/unavailable.png"); + if (m_inErrorState) + return QLatin1String(":/icons/oxygen/unavailable.png"); - return m_icon; + return m_icon; } bool RssFeed::hasCustomIcon() const { - return !m_icon.startsWith(":/"); + return !m_icon.startsWith(":/"); } -void RssFeed::setIconPath(const QString& path) +void RssFeed::setIconPath(const QString &path) { - if (path.isEmpty() || !QFile::exists(path)) - return; - - m_icon = path; + if (!path.isEmpty() && QFile::exists(path)) + m_icon = path; } -RssArticlePtr RssFeed::getItem(const QString& guid) const +RssArticlePtr RssFeed::getItem(const QString &guid) const { - return m_articles.value(guid); + return m_articles.value(guid); } uint RssFeed::count() const { - return m_articles.size(); + return m_articles.size(); } void RssFeed::markAsRead() { - RssArticleHash::ConstIterator it = m_articles.begin(); - RssArticleHash::ConstIterator itend = m_articles.end(); - for ( ; it != itend; ++it) { - it.value()->markAsRead(); - } - m_unreadCount = 0; - m_manager->forwardFeedInfosChanged(m_url, displayName(), 0); + RssArticleHash::ConstIterator it = m_articles.begin(); + RssArticleHash::ConstIterator itend = m_articles.end(); + for ( ; it != itend; ++it) { + it.value()->markAsRead(); + } + m_unreadCount = 0; + m_manager->forwardFeedInfosChanged(m_url, displayName(), 0); } void RssFeed::markAsDirty(bool dirty) { - m_dirty = dirty; + m_dirty = dirty; } uint RssFeed::unreadCount() const { - return m_unreadCount; + return m_unreadCount; } RssArticleList RssFeed::articleListByDateDesc() const { - return m_articlesByDate; + return m_articlesByDate; +} + +const RssArticleHash &RssFeed::articleHash() const +{ + return m_articles; } RssArticleList RssFeed::unreadArticleListByDateDesc() const { - RssArticleList unread_news; + RssArticleList unreadNews; - RssArticleList::ConstIterator it = m_articlesByDate.begin(); - RssArticleList::ConstIterator itend = m_articlesByDate.end(); - for ( ; it != itend; ++it) { - if (!(*it)->isRead()) - unread_news << *it; - } - return unread_news; + RssArticleList::ConstIterator it = m_articlesByDate.begin(); + RssArticleList::ConstIterator itend = m_articlesByDate.end(); + for ( ; it != itend; ++it) { + if (!(*it)->isRead()) + unreadNews << *it; + } + return unreadNews; } // download the icon from the address QString RssFeed::iconUrl() const { - // XXX: This works for most sites but it is not perfect - return QString("http://") + QUrl(m_url).host() + QString("/favicon.ico"); + // XXX: This works for most sites but it is not perfect + return QString("http://") + QUrl(m_url).host() + QString("/favicon.ico"); } // read and store the downloaded rss' informations void RssFeed::handleFinishedDownload(const QString &url, const QString &filePath) { - if (url == m_url) { - qDebug() << Q_FUNC_INFO << "Successfully downloaded RSS feed at" << url; - // Parse the download RSS - m_manager->rssParser()->parseRssFile(m_url, filePath); - } else if (url == m_iconUrl) { - m_icon = filePath; - qDebug() << Q_FUNC_INFO << "icon path:" << m_icon; - m_manager->forwardFeedIconChanged(m_url, m_icon); - } + if (url == m_url) { + qDebug() << Q_FUNC_INFO << "Successfully downloaded RSS feed at" << url; + // Parse the download RSS + m_manager->rssParser()->parseRssFile(m_url, filePath); + } + else if (url == m_iconUrl) { + m_icon = filePath; + qDebug() << Q_FUNC_INFO << "icon path:" << m_icon; + m_manager->forwardFeedIconChanged(m_url, m_icon); + } } void RssFeed::handleDownloadFailure(const QString &url, const QString &error) { - if (url != m_url) return; + if (url != m_url) return; - m_inErrorState = true; - m_loading = false; - m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount); - qWarning() << "Failed to download RSS feed at" << url; - qWarning() << "Reason:" << error; + m_inErrorState = true; + m_loading = false; + m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount); + qWarning() << "Failed to download RSS feed at" << url; + qWarning() << "Reason:" << error; } -void RssFeed::handleFeedTitle(const QString& feedUrl, const QString& title) +void RssFeed::handleFeedTitle(const QString &feedUrl, const QString &title) { - if (feedUrl != m_url) - return; + if (feedUrl != m_url) return; + if (m_title == title) return; - if (m_title == title) - return; + m_title = title; - m_title = title; - - // Notify that we now have something better than a URL to display - if (m_alias.isEmpty()) - m_manager->forwardFeedInfosChanged(feedUrl, title, m_unreadCount); + // Notify that we now have something better than a URL to display + if (m_alias.isEmpty()) + m_manager->forwardFeedInfosChanged(feedUrl, title, m_unreadCount); } -void RssFeed::downloadArticleTorrentIfMatching(RssDownloadRuleList* rules, const RssArticlePtr& article) +void RssFeed::downloadArticleTorrentIfMatching(RssDownloadRuleList *rules, const RssArticlePtr &article) { - Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled()); - RssDownloadRulePtr matching_rule = rules->findMatchingRule(m_url, article->title()); - if (!matching_rule) - return; + Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled()); + RssDownloadRulePtr matchingRule = rules->findMatchingRule(m_url, article->title()); + if (!matchingRule) return; + + if (matchingRule->ignoreDays() > 0) { + QDateTime lastMatch = matchingRule->lastMatch(); + if (lastMatch.isValid()) { + if (QDateTime::currentDateTime() < lastMatch.addDays(matchingRule->ignoreDays())) { + connect(article.data(), SIGNAL(articleWasRead()), SLOT(handleArticleStateChanged()), Qt::UniqueConnection); + article->markAsRead(); + return; + } + } + } - if (matching_rule->ignoreDays() > 0) { - QDateTime lastMatch = matching_rule->lastMatch(); - if (lastMatch.isValid()) { - if (QDateTime::currentDateTime() < lastMatch.addDays(matching_rule->ignoreDays())) { - connect(article.data(), SIGNAL(articleWasRead()), SLOT(handleArticleStateChanged()), Qt::UniqueConnection); + matchingRule->setLastMatch(QDateTime::currentDateTime()); + rules->saveRulesToStorage(); + // Download the torrent + const QString &torrentUrl = article->torrentUrl(); + if (torrentUrl.isEmpty()) { + Logger::instance()->addMessage(tr("Automatic download of '%1' from '%2' RSS feed failed because it doesn't contain a torrent or a magnet link...").arg(article->title()).arg(displayName()), Log::WARNING); article->markAsRead(); return; - } } - } - matching_rule->setLastMatch(QDateTime::currentDateTime()); - rules->saveRulesToStorage(); - // Download the torrent - const QString& torrent_url = article->torrentUrl(); - if (torrent_url.isEmpty()) { - Logger::instance()->addMessage(tr("Automatic download of '%1' from '%2' RSS feed failed because it doesn't contain a torrent or a magnet link...").arg(article->title()).arg(displayName()), Log::WARNING); - article->markAsRead(); - return; - } - - Logger::instance()->addMessage(tr("Automatically downloading '%1' torrent from '%2' RSS feed...").arg(article->title()).arg(displayName())); - connect(article.data(), SIGNAL(articleWasRead()), SLOT(handleArticleStateChanged()), Qt::UniqueConnection); - if (BitTorrent::MagnetUri(torrent_url).isValid()) - article->markAsRead(); - else - connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFinished(QString)), article.data(), SLOT(handleTorrentDownloadSuccess(const QString&)), Qt::UniqueConnection); - - BitTorrent::AddTorrentParams params; - params.savePath = matching_rule->savePath(); - params.label = matching_rule->label(); - if (matching_rule->addPaused() == RssDownloadRule::ALWAYS_PAUSED) - params.addPaused = TriStateBool::True; - else if (matching_rule->addPaused() == RssDownloadRule::NEVER_PAUSED) - params.addPaused = TriStateBool::False; - BitTorrent::Session::instance()->addTorrent(torrent_url, params); + + Logger::instance()->addMessage(tr("Automatically downloading '%1' torrent from '%2' RSS feed...").arg(article->title()).arg(displayName())); + connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFinished(QString)), article.data(), SLOT(handleTorrentDownloadSuccess(const QString &)), Qt::UniqueConnection); + if (BitTorrent::MagnetUri(torrent_url).isValid()) + article->markAsRead(); + else + connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFinished(QString)), article.data(), SLOT(handleTorrentDownloadSuccess(const QString&)), Qt::UniqueConnection); + + BitTorrent::AddTorrentParams params; + params.savePath = matchingRule->savePath(); + params.label = matchingRule->label(); + if (matchingRule->addPaused() == RssDownloadRule::ALWAYS_PAUSED) + params.addPaused = TriStateBool::True; + else if (matchingRule->addPaused() == RssDownloadRule::NEVER_PAUSED) + params.addPaused = TriStateBool::False; + BitTorrent::Session::instance()->addTorrent(torrentUrl, params); } void RssFeed::recheckRssItemsForDownload() { - Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled()); - RssDownloadRuleList* rules = m_manager->downloadRules(); - foreach (const RssArticlePtr& article, m_articlesByDate) { - if (!article->isRead()) - downloadArticleTorrentIfMatching(rules, article); - } + Q_ASSERT(Preferences::instance()->isRssDownloadingEnabled()); + RssDownloadRuleList *rules = m_manager->downloadRules(); + foreach (const RssArticlePtr &article, m_articlesByDate) { + if (!article->isRead()) + downloadArticleTorrentIfMatching(rules, article); + } } -void RssFeed::handleNewArticle(const QString& feedUrl, const QVariantHash& articleData) +void RssFeed::handleNewArticle(const QString &feedUrl, const QVariantHash &articleData) { - if (feedUrl != m_url) - return; + if (feedUrl != m_url) return; - RssArticlePtr article = hashToRssArticle(this, articleData); - if (article.isNull()) { - qDebug() << "Article hash corrupted or guid is uncomputable; feed url: " << feedUrl; - return; - } - Q_ASSERT(article); - addArticle(article); + RssArticlePtr article = RssArticle::fromHash(this, articleData); + if (article.isNull()) { + qDebug() << "Article hash corrupted or guid is uncomputable; feed url: " << feedUrl; + return; + } + Q_ASSERT(article); + addArticle(article); - m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount); - // FIXME: We should forward the information here but this would seriously decrease - // performance with current design. - //m_manager->forwardFeedContentChanged(m_url); + m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount); + // FIXME: We should forward the information here but this would seriously decrease + // performance with current design. + //m_manager->forwardFeedContentChanged(m_url); } -void RssFeed::handleFeedParsingFinished(const QString& feedUrl, const QString& error) +void RssFeed::handleFeedParsingFinished(const QString &feedUrl, const QString &error) { - if (feedUrl != m_url) - return; + if (feedUrl != m_url) return; - if (!error.isEmpty()) { - qWarning() << "Failed to parse RSS feed at" << feedUrl; - qWarning() << "Reason:" << error; - } + if (!error.isEmpty()) { + qWarning() << "Failed to parse RSS feed at" << feedUrl; + qWarning() << "Reason:" << error; + } - m_loading = false; - m_inErrorState = !error.isEmpty(); + m_loading = false; + m_inErrorState = !error.isEmpty(); - m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount); - // XXX: Would not be needed if we did this in handleNewArticle() instead - m_manager->forwardFeedContentChanged(m_url); + m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount); + // XXX: Would not be needed if we did this in handleNewArticle() instead + m_manager->forwardFeedContentChanged(m_url); - saveItemsToDisk(); + saveItemsToDisk(); } void RssFeed::handleArticleStateChanged() { - m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount); + m_manager->forwardFeedInfosChanged(m_url, displayName(), m_unreadCount); } void RssFeed::decrementUnreadCount() { - --m_unreadCount; + --m_unreadCount; } diff --git a/src/base/rss/rssfeed.h b/src/base/rss/rssfeed.h index 84e95119f..70fffa6b5 100644 --- a/src/base/rss/rssfeed.h +++ b/src/base/rss/rssfeed.h @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez, Arnaud Demaiziere + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2010 Arnaud Demaiziere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -39,6 +40,7 @@ #include "rssfile.h" +class RssFolder; class RssFeed; class RssManager; class RssDownloadRuleList; @@ -47,69 +49,69 @@ typedef QHash RssArticleHash; typedef QSharedPointer RssFeedPtr; typedef QList RssFeedList; -bool rssArticleDateRecentThan(const RssArticlePtr& left, const RssArticlePtr& right); +bool rssArticleDateRecentThan(const RssArticlePtr &left, const RssArticlePtr &right); -class RssFeed: public QObject, public RssFile { - Q_OBJECT +class RssFeed: public QObject, public RssFile +{ + Q_OBJECT public: - RssFeed(RssManager* manager, RssFolder* m_parent, const QString& url); - virtual ~RssFeed(); - virtual RssFolder* parent() const { return m_parent; } - virtual void setParent(RssFolder* parent) { m_parent = parent; } - bool refresh(); - virtual QString id() const { return m_url; } - virtual void removeAllSettings(); - virtual void saveItemsToDisk(); - bool isLoading() const; - QString title() const; - virtual void rename(const QString &alias); - virtual QString displayName() const; - QString url() const; - virtual QString iconPath() const; - bool hasCustomIcon() const; - void setIconPath(const QString &pathHierarchy); - RssArticlePtr getItem(const QString &guid) const; - uint count() const; - virtual void markAsRead(); - void markAsDirty(bool dirty = true); - virtual uint unreadCount() const; - virtual RssArticleList articleListByDateDesc() const; - const RssArticleHash& articleHash() const { return m_articles; } - virtual RssArticleList unreadArticleListByDateDesc() const; - void decrementUnreadCount(); - void recheckRssItemsForDownload(); + RssFeed(RssManager *manager, RssFolder *parent, const QString &url); + ~RssFeed(); + + RssFolder *parent() const; + void setParent(RssFolder *parent); + bool refresh(); + QString id() const; + void removeAllSettings(); + void saveItemsToDisk(); + bool isLoading() const; + QString title() const; + void rename(const QString &newName); + QString displayName() const; + QString url() const; + QString iconPath() const; + bool hasCustomIcon() const; + void setIconPath(const QString &pathHierarchy); + RssArticlePtr getItem(const QString &guid) const; + uint count() const; + void markAsRead(); + void markAsDirty(bool dirty = true); + uint unreadCount() const; + RssArticleList articleListByDateDesc() const; + const RssArticleHash &articleHash() const; + RssArticleList unreadArticleListByDateDesc() const; + void decrementUnreadCount(); + void recheckRssItemsForDownload(); private slots: - void handleFinishedDownload(const QString &url, const QString &filePath); - void handleDownloadFailure(const QString &url, const QString &error); - void handleFeedTitle(const QString& feedUrl, const QString& title); - void handleNewArticle(const QString& feedUrl, const QVariantHash& article); - void handleFeedParsingFinished(const QString& feedUrl, const QString& error); - void handleArticleStateChanged(); + void handleFinishedDownload(const QString &url, const QString &filePath); + void handleDownloadFailure(const QString &url, const QString &error); + void handleFeedTitle(const QString &feedUrl, const QString &title); + void handleNewArticle(const QString &feedUrl, const QVariantHash &article); + void handleFeedParsingFinished(const QString &feedUrl, const QString &error); + void handleArticleStateChanged(); private: - QString iconUrl() const; - void loadItemsFromDisk(); - void addArticle(const RssArticlePtr& article); - void downloadArticleTorrentIfMatching(RssDownloadRuleList* rules, const RssArticlePtr& article); + QString iconUrl() const; + void loadItemsFromDisk(); + void addArticle(const RssArticlePtr &article); + void downloadArticleTorrentIfMatching(RssDownloadRuleList *rules, const RssArticlePtr &article); private: - RssManager* m_manager; - RssArticleHash m_articles; - RssArticleList m_articlesByDate; // Articles sorted by date (more recent first) - RssFolder* m_parent; - QString m_title; - QString m_url; - QString m_alias; - QString m_icon; - QString m_iconUrl; - uint m_unreadCount; - bool m_dirty; - bool m_inErrorState; - bool m_loading; - + RssManager *m_manager; + RssArticleHash m_articles; + RssArticleList m_articlesByDate; // Articles sorted by date (more recent first) + RssFolder *m_parent; + QString m_title; + QString m_url; + QString m_alias; + QString m_icon; + QString m_iconUrl; + uint m_unreadCount; + bool m_dirty; + bool m_inErrorState; + bool m_loading; }; - #endif // RSSFEED_H diff --git a/src/base/rss/rssfile.cpp b/src/base/rss/rssfile.cpp index ac090e0ee..187dfd303 100644 --- a/src/base/rss/rssfile.cpp +++ b/src/base/rss/rssfile.cpp @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez, Arnaud Demaiziere + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2010 Arnaud Demaiziere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -31,10 +32,13 @@ #include "rssfolder.h" #include "rssfile.h" -QStringList RssFile::pathHierarchy() const { - QStringList path; - if (parent()) - path << parent()->pathHierarchy(); - path << id(); - return path; +RssFile::~RssFile() {} + +QStringList RssFile::pathHierarchy() const +{ + QStringList path; + if (parent()) + path << parent()->pathHierarchy(); + path << id(); + return path; } diff --git a/src/base/rss/rssfile.h b/src/base/rss/rssfile.h index 9b08d00f9..ff2f0d913 100644 --- a/src/base/rss/rssfile.h +++ b/src/base/rss/rssfile.h @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez, Arnaud Demaiziere + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2010 Arnaud Demaiziere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -47,28 +48,30 @@ typedef QList RssFileList; /** * Parent interface for RssFolder and RssFeed. */ -class RssFile { +class RssFile +{ public: - virtual ~RssFile() {} + virtual ~RssFile(); - virtual uint unreadCount() const = 0; - virtual QString displayName() const = 0; - virtual QString id() const = 0; - virtual QString iconPath() const = 0; - virtual void rename(const QString &new_name) = 0; - virtual void markAsRead() = 0; - virtual RssFolder* parent() const = 0; - virtual void setParent(RssFolder* parent) = 0; - virtual bool refresh() = 0; - virtual RssArticleList articleListByDateDesc() const = 0; - virtual RssArticleList unreadArticleListByDateDesc() const = 0; - virtual void removeAllSettings() = 0; - virtual void saveItemsToDisk() = 0; - virtual void recheckRssItemsForDownload() = 0; - QStringList pathHierarchy() const; + virtual uint unreadCount() const = 0; + virtual QString displayName() const = 0; + virtual QString id() const = 0; + virtual QString iconPath() const = 0; + virtual void rename(const QString &newName) = 0; + virtual void markAsRead() = 0; + virtual RssFolder *parent() const = 0; + virtual void setParent(RssFolder *parent) = 0; + virtual bool refresh() = 0; + virtual RssArticleList articleListByDateDesc() const = 0; + virtual RssArticleList unreadArticleListByDateDesc() const = 0; + virtual void removeAllSettings() = 0; + virtual void saveItemsToDisk() = 0; + virtual void recheckRssItemsForDownload() = 0; + + QStringList pathHierarchy() const; protected: - uint m_unreadCount; + uint m_unreadCount; }; #endif // RSSFILE_H diff --git a/src/base/rss/rssfolder.cpp b/src/base/rss/rssfolder.cpp index a76357623..ac5e2b84d 100644 --- a/src/base/rss/rssfolder.cpp +++ b/src/base/rss/rssfolder.cpp @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez, Arnaud Demaiziere + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2010 Arnaud Demaiziere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -37,226 +38,256 @@ #include "rssarticle.h" #include "rssfolder.h" -RssFolder::RssFolder(RssFolder *parent, const QString &name): m_parent(parent), m_name(name) { +RssFolder::RssFolder(RssFolder *parent, const QString &name) + : m_parent(parent) + , m_name(name) +{ } -RssFolder::~RssFolder() { +RssFolder::~RssFolder() {} + +RssFolder *RssFolder::parent() const +{ + return m_parent; } -unsigned int RssFolder::unreadCount() const { - uint nb_unread = 0; - - RssFileHash::ConstIterator it = m_children.begin(); - RssFileHash::ConstIterator itend = m_children.end(); - for ( ; it != itend; ++it) { - nb_unread += it.value()->unreadCount(); - } - return nb_unread; +void RssFolder::setParent(RssFolder *parent) +{ + m_parent = parent; } -void RssFolder::removeChild(const QString &childId) { - if (m_children.contains(childId)) { - RssFilePtr child = m_children.take(childId); - child->removeAllSettings(); - } +uint RssFolder::unreadCount() const +{ + uint nbUnread = 0; + + RssFileHash::ConstIterator it = m_children.begin(); + RssFileHash::ConstIterator itend = m_children.end(); + for ( ; it != itend; ++it) + nbUnread += it.value()->unreadCount(); + + return nbUnread; } -RssFolderPtr RssFolder::addFolder(const QString &name) { - RssFolderPtr subfolder; - if (!m_children.contains(name)) { - subfolder = RssFolderPtr(new RssFolder(this, name)); - m_children[name] = subfolder; - } else { - subfolder = qSharedPointerDynamicCast(m_children.value(name)); - } - return subfolder; +void RssFolder::removeChild(const QString &childId) +{ + if (m_children.contains(childId)) { + RssFilePtr child = m_children.take(childId); + child->removeAllSettings(); + } } -RssFeedPtr RssFolder::addStream(RssManager* manager, const QString &url) { - qDebug() << Q_FUNC_INFO << manager << url; - RssFeedPtr stream(new RssFeed(manager, this, url)); - Q_ASSERT(stream); - qDebug() << "Stream URL is " << stream->url(); - Q_ASSERT(!m_children.contains(stream->url())); - m_children[stream->url()] = stream; - stream->refresh(); - return stream; +RssFolderPtr RssFolder::addFolder(const QString &name) +{ + RssFolderPtr subfolder; + if (!m_children.contains(name)) { + subfolder = RssFolderPtr(new RssFolder(this, name)); + m_children[name] = subfolder; + } + else { + subfolder = qSharedPointerDynamicCast(m_children.value(name)); + } + return subfolder; } -// Refresh All Children -bool RssFolder::refresh() { - RssFileHash::ConstIterator it = m_children.begin(); - RssFileHash::ConstIterator itend = m_children.end(); - bool refreshed = false; - for ( ; it != itend; ++it) { - if (it.value()->refresh()) - refreshed = true; - } - return refreshed; +RssFeedPtr RssFolder::addStream(RssManager *manager, const QString &url) +{ + qDebug() << Q_FUNC_INFO << manager << url; + RssFeedPtr stream(new RssFeed(manager, this, url)); + Q_ASSERT(stream); + qDebug() << "Stream URL is " << stream->url(); + Q_ASSERT(!m_children.contains(stream->url())); + m_children[stream->url()] = stream; + stream->refresh(); + return stream; } -RssArticleList RssFolder::articleListByDateDesc() const { - RssArticleList news; - - RssFileHash::ConstIterator it = m_children.begin(); - RssFileHash::ConstIterator itend = m_children.end(); - for ( ; it != itend; ++it) { - int n = news.size(); - news << it.value()->articleListByDateDesc(); - std::inplace_merge(news.begin(), news.begin() + n, news.end(), rssArticleDateRecentThan); - } - return news; +// Refresh All Children +bool RssFolder::refresh() +{ + RssFileHash::ConstIterator it = m_children.begin(); + RssFileHash::ConstIterator itend = m_children.end(); + bool refreshed = false; + for ( ; it != itend; ++it) { + if (it.value()->refresh()) + refreshed = true; + } + return refreshed; } -RssArticleList RssFolder::unreadArticleListByDateDesc() const { - RssArticleList unread_news; - - RssFileHash::ConstIterator it = m_children.begin(); - RssFileHash::ConstIterator itend = m_children.end(); - for ( ; it != itend; ++it) { - int n = unread_news.size(); - unread_news << it.value()->unreadArticleListByDateDesc(); - std::inplace_merge(unread_news.begin(), unread_news.begin() + n, unread_news.end(), rssArticleDateRecentThan); - } - return unread_news; +RssArticleList RssFolder::articleListByDateDesc() const +{ + RssArticleList news; + + RssFileHash::ConstIterator it = m_children.begin(); + RssFileHash::ConstIterator itend = m_children.end(); + for ( ; it != itend; ++it) { + int n = news.size(); + news << it.value()->articleListByDateDesc(); + std::inplace_merge(news.begin(), news.begin() + n, news.end(), rssArticleDateRecentThan); + } + return news; } -RssFileList RssFolder::getContent() const { - return m_children.values(); +RssArticleList RssFolder::unreadArticleListByDateDesc() const +{ + RssArticleList unreadNews; + + RssFileHash::ConstIterator it = m_children.begin(); + RssFileHash::ConstIterator itend = m_children.end(); + for ( ; it != itend; ++it) { + int n = unreadNews.size(); + unreadNews << it.value()->unreadArticleListByDateDesc(); + std::inplace_merge(unreadNews.begin(), unreadNews.begin() + n, unreadNews.end(), rssArticleDateRecentThan); + } + return unreadNews; } -unsigned int RssFolder::getNbFeeds() const { - uint nbFeeds = 0; - - RssFileHash::ConstIterator it = m_children.begin(); - RssFileHash::ConstIterator itend = m_children.end(); - for ( ; it != itend; ++it) { - if (RssFolderPtr folder = qSharedPointerDynamicCast(it.value())) - nbFeeds += folder->getNbFeeds(); - else - ++nbFeeds; // Feed - } - return nbFeeds; +RssFileList RssFolder::getContent() const +{ + return m_children.values(); } -QString RssFolder::displayName() const { - return m_name; +uint RssFolder::getNbFeeds() const +{ + uint nbFeeds = 0; + + RssFileHash::ConstIterator it = m_children.begin(); + RssFileHash::ConstIterator itend = m_children.end(); + for ( ; it != itend; ++it) { + if (RssFolderPtr folder = qSharedPointerDynamicCast(it.value())) + nbFeeds += folder->getNbFeeds(); + else + ++nbFeeds; // Feed + } + return nbFeeds; } -void RssFolder::rename(const QString &new_name) { - if (m_name == new_name) return; - Q_ASSERT(!m_parent->hasChild(new_name)); - if (!m_parent->hasChild(new_name)) { - // Update parent - m_parent->renameChildFolder(m_name, new_name); - // Actually rename - m_name = new_name; - } +QString RssFolder::displayName() const +{ + return m_name; } -void RssFolder::markAsRead() { - RssFileHash::ConstIterator it = m_children.begin(); - RssFileHash::ConstIterator itend = m_children.end(); - for ( ; it != itend; ++it) { - it.value()->markAsRead(); - } +void RssFolder::rename(const QString &newName) +{ + if (m_name == newName) return; + + Q_ASSERT(!m_parent->hasChild(newName)); + if (!m_parent->hasChild(newName)) { + // Update parent + m_parent->renameChildFolder(m_name, newName); + // Actually rename + m_name = newName; + } } -RssFeedList RssFolder::getAllFeeds() const { - RssFeedList streams; +void RssFolder::markAsRead() +{ + RssFileHash::ConstIterator it = m_children.begin(); + RssFileHash::ConstIterator itend = m_children.end(); + for ( ; it != itend; ++it) { + it.value()->markAsRead(); + } +} - RssFileHash::ConstIterator it = m_children.begin(); - RssFileHash::ConstIterator itend = m_children.end(); - for ( ; it != itend; ++it) { - if (RssFeedPtr feed = qSharedPointerDynamicCast(it.value())) { - streams << feed; - } else if (RssFolderPtr folder = qSharedPointerDynamicCast(it.value())) { - streams << folder->getAllFeeds(); +RssFeedList RssFolder::getAllFeeds() const +{ + RssFeedList streams; + + RssFileHash::ConstIterator it = m_children.begin(); + RssFileHash::ConstIterator itend = m_children.end(); + for ( ; it != itend; ++it) { + if (RssFeedPtr feed = qSharedPointerDynamicCast(it.value())) + streams << feed; + else if (RssFolderPtr folder = qSharedPointerDynamicCast(it.value())) + streams << folder->getAllFeeds(); } - } - return streams; + return streams; } -QHash RssFolder::getAllFeedsAsHash() const { - QHash ret; - - RssFileHash::ConstIterator it = m_children.begin(); - RssFileHash::ConstIterator itend = m_children.end(); - for ( ; it != itend; ++it) { - if (RssFeedPtr feed = qSharedPointerDynamicCast(it.value())) { - qDebug() << Q_FUNC_INFO << feed->url(); - ret[feed->url()] = feed; - } else if (RssFolderPtr folder = qSharedPointerDynamicCast(it.value())) { - ret.unite(folder->getAllFeedsAsHash()); +QHash RssFolder::getAllFeedsAsHash() const +{ + QHash ret; + + RssFileHash::ConstIterator it = m_children.begin(); + RssFileHash::ConstIterator itend = m_children.end(); + for ( ; it != itend; ++it) { + if (RssFeedPtr feed = qSharedPointerDynamicCast(it.value())) { + qDebug() << Q_FUNC_INFO << feed->url(); + ret[feed->url()] = feed; + } + else if (RssFolderPtr folder = qSharedPointerDynamicCast(it.value())) { + ret.unite(folder->getAllFeedsAsHash()); + } } - } - return ret; + return ret; } -void RssFolder::addFile(const RssFilePtr& item) { - if (RssFeedPtr feed = qSharedPointerDynamicCast(item)) { - Q_ASSERT(!m_children.contains(feed->url())); - m_children[feed->url()] = item; - qDebug("Added feed %s to folder ./%s", qPrintable(feed->url()), qPrintable(m_name)); - } else if (RssFolderPtr folder = qSharedPointerDynamicCast(item)) { - Q_ASSERT(!m_children.contains(folder->displayName())); - m_children[folder->displayName()] = item; - qDebug("Added folder %s to folder ./%s", qPrintable(folder->displayName()), qPrintable(m_name)); - } - // Update parent - item->setParent(this); +void RssFolder::addFile(const RssFilePtr &item) +{ + if (RssFeedPtr feed = qSharedPointerDynamicCast(item)) { + Q_ASSERT(!m_children.contains(feed->url())); + m_children[feed->url()] = item; + qDebug("Added feed %s to folder ./%s", qPrintable(feed->url()), qPrintable(m_name)); + } + else if (RssFolderPtr folder = qSharedPointerDynamicCast(item)) { + Q_ASSERT(!m_children.contains(folder->displayName())); + m_children[folder->displayName()] = item; + qDebug("Added folder %s to folder ./%s", qPrintable(folder->displayName()), qPrintable(m_name)); + } + // Update parent + item->setParent(this); } -void RssFolder::removeAllItems() { - m_children.clear(); +void RssFolder::removeAllItems() +{ + m_children.clear(); } -void RssFolder::removeAllSettings() { - RssFileHash::ConstIterator it = m_children.begin(); - RssFileHash::ConstIterator itend = m_children.end(); - for ( ; it != itend; ++it) { - it.value()->removeAllSettings(); - } +void RssFolder::removeAllSettings() +{ + RssFileHash::ConstIterator it = m_children.begin(); + RssFileHash::ConstIterator itend = m_children.end(); + for ( ; it != itend; ++it) + it.value()->removeAllSettings(); } void RssFolder::saveItemsToDisk() { - foreach (const RssFilePtr& child, m_children.values()) { - child->saveItemsToDisk(); - } + foreach (const RssFilePtr &child, m_children.values()) + child->saveItemsToDisk(); } QString RssFolder::id() const { - return m_name; + return m_name; } QString RssFolder::iconPath() const { - return IconProvider::instance()->getIconPath("inode-directory"); + return IconProvider::instance()->getIconPath("inode-directory"); } -bool RssFolder::hasChild(const QString &childId) { - return m_children.contains(childId); +bool RssFolder::hasChild(const QString &childId) +{ + return m_children.contains(childId); } -void RssFolder::renameChildFolder(const QString &old_name, const QString &new_name) +void RssFolder::renameChildFolder(const QString &oldName, const QString &newName) { - Q_ASSERT(m_children.contains(old_name)); - RssFilePtr folder = m_children.take(old_name); - m_children[new_name] = folder; + Q_ASSERT(m_children.contains(oldName)); + RssFilePtr folder = m_children.take(oldName); + m_children[newName] = folder; } RssFilePtr RssFolder::takeChild(const QString &childId) { - return m_children.take(childId); + return m_children.take(childId); } void RssFolder::recheckRssItemsForDownload() { - RssFileHash::ConstIterator it = m_children.begin(); - RssFileHash::ConstIterator itend = m_children.end(); - for ( ; it != itend; ++it) { - it.value()->recheckRssItemsForDownload(); - } + RssFileHash::ConstIterator it = m_children.begin(); + RssFileHash::ConstIterator itend = m_children.end(); + for ( ; it != itend; ++it) + it.value()->recheckRssItemsForDownload(); } diff --git a/src/base/rss/rssfolder.h b/src/base/rss/rssfolder.h index 85e8c7ca0..137ee5e9c 100644 --- a/src/base/rss/rssfolder.h +++ b/src/base/rss/rssfolder.h @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez, Arnaud Demaiziere + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2010 Arnaud Demaiziere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -45,45 +46,47 @@ typedef QSharedPointer RssFeedPtr; typedef QSharedPointer RssFolderPtr; typedef QList RssFeedList; -class RssFolder: public QObject, public RssFile { - Q_OBJECT +class RssFolder: public QObject, public RssFile +{ + Q_OBJECT public: - RssFolder(RssFolder *parent = 0, const QString &name = QString()); - virtual ~RssFolder(); - virtual RssFolder* parent() const { return m_parent; } - virtual void setParent(RssFolder* parent) { m_parent = parent; } - virtual unsigned int unreadCount() const; - RssFeedPtr addStream(RssManager* manager, const QString &url); - RssFolderPtr addFolder(const QString &name); - unsigned int getNbFeeds() const; - RssFileList getContent() const; - RssFeedList getAllFeeds() const; - QHash getAllFeedsAsHash() const; - virtual QString displayName() const; - virtual QString id() const; - virtual QString iconPath() const; - bool hasChild(const QString &childId); - virtual RssArticleList articleListByDateDesc() const; - virtual RssArticleList unreadArticleListByDateDesc() const; - virtual void removeAllSettings(); - virtual void saveItemsToDisk(); - void removeAllItems(); - void renameChildFolder(const QString &old_name, const QString &new_name); - RssFilePtr takeChild(const QString &childId); - void recheckRssItemsForDownload(); + explicit RssFolder(RssFolder *parent = 0, const QString &name = QString()); + ~RssFolder(); + + RssFolder *parent() const; + void setParent(RssFolder *parent); + uint unreadCount() const; + RssFeedPtr addStream(RssManager *manager, const QString &url); + RssFolderPtr addFolder(const QString &name); + uint getNbFeeds() const; + RssFileList getContent() const; + RssFeedList getAllFeeds() const; + QHash getAllFeedsAsHash() const; + QString displayName() const; + QString id() const; + QString iconPath() const; + bool hasChild(const QString &childId); + RssArticleList articleListByDateDesc() const; + RssArticleList unreadArticleListByDateDesc() const; + void removeAllSettings(); + void saveItemsToDisk(); + void removeAllItems(); + void renameChildFolder(const QString &oldName, const QString &newName); + RssFilePtr takeChild(const QString &childId); + void recheckRssItemsForDownload(); public slots: - virtual bool refresh(); - void addFile(const RssFilePtr& item); - void removeChild(const QString &childId); - virtual void rename(const QString &new_name); - virtual void markAsRead(); + bool refresh(); + void addFile(const RssFilePtr &item); + void removeChild(const QString &childId); + void rename(const QString &newName); + void markAsRead(); private: - RssFolder *m_parent; - QString m_name; - RssFileHash m_children; + RssFolder *m_parent; + QString m_name; + RssFileHash m_children; }; #endif // RSSFOLDER_H diff --git a/src/base/rss/rssmanager.cpp b/src/base/rss/rssmanager.cpp index f00457189..248caabc8 100644 --- a/src/base/rss/rssmanager.cpp +++ b/src/base/rss/rssmanager.cpp @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez, Arnaud Demaiziere + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2010 Arnaud Demaiziere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -30,8 +31,8 @@ #include +#include "base/logger.h" #include "base/preferences.h" -#include "base/bittorrent/session.h" #include "rssfeed.h" #include "rssarticle.h" #include "rssdownloadrulelist.h" @@ -40,122 +41,124 @@ static const int MSECS_PER_MIN = 60000; -RssManager::RssManager(): - m_downloadRules(new RssDownloadRuleList), - m_rssParser(new RssParser(this)) +RssManager::RssManager() + : m_downloadRules(new RssDownloadRuleList) + , m_rssParser(new RssParser(this)) { - connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(refresh())); - m_refreshInterval = Preferences::instance()->getRSSRefreshInterval(); - m_refreshTimer.start(m_refreshInterval * MSECS_PER_MIN); + connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(refresh())); + m_refreshInterval = Preferences::instance()->getRSSRefreshInterval(); + m_refreshTimer.start(m_refreshInterval * MSECS_PER_MIN); } RssManager::~RssManager() { - qDebug("Deleting RSSManager..."); - delete m_downloadRules; - delete m_rssParser; - saveItemsToDisk(); - saveStreamList(); - qDebug("RSSManager deleted"); + qDebug("Deleting RSSManager..."); + delete m_downloadRules; + delete m_rssParser; + saveItemsToDisk(); + saveStreamList(); + qDebug("RSSManager deleted"); } -RssParser* RssManager::rssParser() const +RssParser *RssManager::rssParser() const { - return m_rssParser; + return m_rssParser; } void RssManager::updateRefreshInterval(uint val) { - if (m_refreshInterval != val) { - m_refreshInterval = val; - m_refreshTimer.start(m_refreshInterval*60000); - qDebug("New RSS refresh interval is now every %dmin", m_refreshInterval); - } + if (m_refreshInterval != val) { + m_refreshInterval = val; + m_refreshTimer.start(m_refreshInterval*60000); + qDebug("New RSS refresh interval is now every %dmin", m_refreshInterval); + } } void RssManager::loadStreamList() { - const Preferences* const pref = Preferences::instance(); - const QStringList streamsUrl = pref->getRssFeedsUrls(); - const QStringList aliases = pref->getRssFeedsAliases(); - if (streamsUrl.size() != aliases.size()) { - std::cerr << "Corrupted Rss list, not loading it\n"; - return; - } - uint i = 0; - qDebug() << Q_FUNC_INFO << streamsUrl; - foreach (QString s, streamsUrl) { - QStringList path = s.split("\\", QString::SkipEmptyParts); - if (path.empty()) continue; - const QString feed_url = path.takeLast(); - qDebug() << "Feed URL:" << feed_url; - // Create feed path (if it does not exists) - RssFolder* feed_parent = this; - foreach (const QString &folder_name, path) { - qDebug() << "Adding parent folder:" << folder_name; - feed_parent = feed_parent->addFolder(folder_name).data(); + const Preferences *const pref = Preferences::instance(); + const QStringList streamsUrl = pref->getRssFeedsUrls(); + const QStringList aliases = pref->getRssFeedsAliases(); + if (streamsUrl.size() != aliases.size()) { + Logger::instance()->addMessage("Corrupted RSS list, not loading it.", Log::WARNING); + return; } - // Create feed - qDebug() << "Adding feed to parent folder"; - RssFeedPtr stream = feed_parent->addStream(this, feed_url); - const QString& alias = aliases[i]; - if (!alias.isEmpty()) { - stream->rename(alias); + + uint i = 0; + qDebug() << Q_FUNC_INFO << streamsUrl; + foreach (QString s, streamsUrl) { + QStringList path = s.split("\\", QString::SkipEmptyParts); + if (path.empty()) continue; + + const QString feedUrl = path.takeLast(); + qDebug() << "Feed URL:" << feedUrl; + // Create feed path (if it does not exists) + RssFolder *feedParent = this; + foreach (const QString &folderName, path) { + qDebug() << "Adding parent folder:" << folderName; + feedParent = feedParent->addFolder(folderName).data(); + } + // Create feed + qDebug() << "Adding feed to parent folder"; + RssFeedPtr stream = feedParent->addStream(this, feedUrl); + const QString &alias = aliases[i]; + if (!alias.isEmpty()) + stream->rename(alias); + ++i; } - ++i; - } - qDebug("NB RSS streams loaded: %d", streamsUrl.size()); + qDebug("NB RSS streams loaded: %d", streamsUrl.size()); } -void RssManager::forwardFeedContentChanged(const QString& url) +void RssManager::forwardFeedContentChanged(const QString &url) { - emit feedContentChanged(url); + emit feedContentChanged(url); } -void RssManager::forwardFeedInfosChanged(const QString& url, const QString& displayName, uint unreadCount) +void RssManager::forwardFeedInfosChanged(const QString &url, const QString &displayName, uint unreadCount) { - emit feedInfosChanged(url, displayName, unreadCount); + emit feedInfosChanged(url, displayName, unreadCount); } -void RssManager::forwardFeedIconChanged(const QString& url, const QString& iconPath) +void RssManager::forwardFeedIconChanged(const QString &url, const QString &iconPath) { - emit feedIconChanged(url, iconPath); + emit feedIconChanged(url, iconPath); } -void RssManager::moveFile(const RssFilePtr& file, const RssFolderPtr& destinationFolder) +void RssManager::moveFile(const RssFilePtr &file, const RssFolderPtr &destinationFolder) { - RssFolder* src_folder = file->parent(); - if (destinationFolder != src_folder) { - // Remove reference in old folder - src_folder->takeChild(file->id()); - // add to new Folder - destinationFolder->addFile(file); - } else { - qDebug("Nothing to move, same destination folder"); - } + RssFolder *srcFolder = file->parent(); + if (destinationFolder != srcFolder) { + // Remove reference in old folder + srcFolder->takeChild(file->id()); + // add to new Folder + destinationFolder->addFile(file); + } + else { + qDebug("Nothing to move, same destination folder"); + } } void RssManager::saveStreamList() const { - QStringList streamsUrl; - QStringList aliases; - RssFeedList streams = getAllFeeds(); - foreach (const RssFeedPtr& stream, streams) { - // This backslash has nothing to do with path handling - QString stream_path = stream->pathHierarchy().join("\\"); - if (stream_path.isNull()) - stream_path = ""; - qDebug("Saving stream path: %s", qPrintable(stream_path)); - streamsUrl << stream_path; - aliases << stream->displayName(); - } - Preferences* const pref = Preferences::instance(); - pref->setRssFeedsUrls(streamsUrl); - pref->setRssFeedsAliases(aliases); + QStringList streamsUrl; + QStringList aliases; + RssFeedList streams = getAllFeeds(); + foreach (const RssFeedPtr &stream, streams) { + // This backslash has nothing to do with path handling + QString streamPath = stream->pathHierarchy().join("\\"); + if (streamPath.isNull()) + streamPath = ""; + qDebug("Saving stream path: %s", qPrintable(streamPath)); + streamsUrl << streamPath; + aliases << stream->displayName(); + } + Preferences *const pref = Preferences::instance(); + pref->setRssFeedsUrls(streamsUrl); + pref->setRssFeedsAliases(aliases); } -RssDownloadRuleList* RssManager::downloadRules() const +RssDownloadRuleList *RssManager::downloadRules() const { - Q_ASSERT(m_downloadRules); - return m_downloadRules; + Q_ASSERT(m_downloadRules); + return m_downloadRules; } diff --git a/src/base/rss/rssmanager.h b/src/base/rss/rssmanager.h index 4a8252ccb..5fff13a65 100644 --- a/src/base/rss/rssmanager.h +++ b/src/base/rss/rssmanager.h @@ -1,6 +1,7 @@ /* - * Bittorrent Client using Qt4 and libtorrent. - * Copyright (C) 2010 Christophe Dumez, Arnaud Demaiziere + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2010 Christophe Dumez + * Copyright (C) 2010 Arnaud Demaiziere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -38,39 +39,40 @@ class RssDownloadRuleList; class RssParser; - class RssManager; + typedef QSharedPointer RssManagerPtr; -class RssManager: public RssFolder { - Q_OBJECT +class RssManager: public RssFolder +{ + Q_OBJECT public: - RssManager(); - virtual ~RssManager(); + RssManager(); + ~RssManager(); - RssParser* rssParser() const; - RssDownloadRuleList* downloadRules() const; + RssParser *rssParser() const; + RssDownloadRuleList *downloadRules() const; public slots: - void loadStreamList(); - void saveStreamList() const; - void forwardFeedContentChanged(const QString& url); - void forwardFeedInfosChanged(const QString& url, const QString& displayName, uint unreadCount); - void forwardFeedIconChanged(const QString& url, const QString& iconPath); - void moveFile(const RssFilePtr& file, const RssFolderPtr& destinationFolder); - void updateRefreshInterval(uint val); + void loadStreamList(); + void saveStreamList() const; + void forwardFeedContentChanged(const QString &url); + void forwardFeedInfosChanged(const QString &url, const QString &displayName, uint unreadCount); + void forwardFeedIconChanged(const QString &url, const QString &iconPath); + void moveFile(const RssFilePtr &file, const RssFolderPtr &destinationFolder); + void updateRefreshInterval(uint val); signals: - void feedContentChanged(const QString& url); - void feedInfosChanged(const QString& url, const QString& displayName, uint unreadCount); - void feedIconChanged(const QString& url, const QString& iconPath); + void feedContentChanged(const QString &url); + void feedInfosChanged(const QString &url, const QString &displayName, uint unreadCount); + void feedIconChanged(const QString &url, const QString &iconPath); private: - QTimer m_refreshTimer; - uint m_refreshInterval; - RssDownloadRuleList* m_downloadRules; - RssParser* m_rssParser; + QTimer m_refreshTimer; + uint m_refreshInterval; + RssDownloadRuleList *m_downloadRules; + RssParser *m_rssParser; }; #endif // RSSMANAGER_H diff --git a/src/base/rss/rssparser.cpp b/src/base/rss/rssparser.cpp index 5929684e4..5f72d6c6a 100644 --- a/src/base/rss/rssparser.cpp +++ b/src/base/rss/rssparser.cpp @@ -37,475 +37,505 @@ #include "base/utils/fs.h" #include "rssparser.h" -struct ParsingJob { - QString feedUrl; - QString filePath; +struct ParsingJob +{ + QString feedUrl; + QString filePath; }; static const char shortDay[][4] = { - "Mon", "Tue", "Wed", - "Thu", "Fri", "Sat", - "Sun" + "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat", + "Sun" }; + static const char longDay[][10] = { - "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday", - "Sunday" + "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday", + "Sunday" }; + static const char shortMonth[][4] = { - "Jan", "Feb", "Mar", "Apr", - "May", "Jun", "Jul", "Aug", - "Sep", "Oct", "Nov", "Dec" + "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; -// Ported to Qt4 from KDElibs4 -QDateTime RssParser::parseDate(const QString &string) { - const QString str = string.trimmed(); - if (str.isEmpty()) - return QDateTime::currentDateTime(); - - int nyear = 6; // indexes within string to values - int nmonth = 4; - int nday = 2; - int nwday = 1; - int nhour = 7; - int nmin = 8; - int nsec = 9; - // Also accept obsolete form "Weekday, DD-Mon-YY HH:MM:SS ±hhmm" - QRegExp rx("^(?:([A-Z][a-z]+),\\s*)?(\\d{1,2})(\\s+|-)([^-\\s]+)(\\s+|-)(\\d{2,4})\\s+(\\d\\d):(\\d\\d)(?::(\\d\\d))?\\s+(\\S+)$"); - QStringList parts; - if (!str.indexOf(rx)) { - // Check that if date has '-' separators, both separators are '-'. - parts = rx.capturedTexts(); - bool h1 = (parts[3] == QLatin1String("-")); - bool h2 = (parts[5] == QLatin1String("-")); - if (h1 != h2) - return QDateTime::currentDateTime(); - } else { - // Check for the obsolete form "Wdy Mon DD HH:MM:SS YYYY" - rx = QRegExp("^([A-Z][a-z]+)\\s+(\\S+)\\s+(\\d\\d)\\s+(\\d\\d):(\\d\\d):(\\d\\d)\\s+(\\d\\d\\d\\d)$"); - if (str.indexOf(rx)) - return QDateTime::currentDateTime(); - nyear = 7; - nmonth = 2; - nday = 3; - nwday = 1; - nhour = 4; - nmin = 5; - nsec = 6; - parts = rx.capturedTexts(); - } - bool ok[4]; - const int day = parts[nday].toInt(&ok[0]); - int year = parts[nyear].toInt(&ok[1]); - const int hour = parts[nhour].toInt(&ok[2]); - const int minute = parts[nmin].toInt(&ok[3]); - if (!ok[0] || !ok[1] || !ok[2] || !ok[3]) - return QDateTime::currentDateTime(); - int second = 0; - if (!parts[nsec].isEmpty()) { - second = parts[nsec].toInt(&ok[0]); - if (!ok[0]) - return QDateTime::currentDateTime(); - } - bool leapSecond = (second == 60); - if (leapSecond) - second = 59; // apparently a leap second - validate below, once time zone is known - int month = 0; - for ( ; month < 12 && parts[nmonth] != shortMonth[month]; ++month) ; - int dayOfWeek = -1; - if (!parts[nwday].isEmpty()) { - // Look up the weekday name - while (++dayOfWeek < 7 && shortDay[dayOfWeek] != parts[nwday]) ; - if (dayOfWeek >= 7) - for (dayOfWeek = 0; dayOfWeek < 7 && longDay[dayOfWeek] != parts[nwday]; ++dayOfWeek) ; - } - // if (month >= 12 || dayOfWeek >= 7 - // || (dayOfWeek < 0 && format == RFCDateDay)) - // return QDateTime; - int i = parts[nyear].size(); - if (i < 4) { - // It's an obsolete year specification with less than 4 digits - year += (i == 2 && year < 50) ? 2000: 1900; - } - - // Parse the UTC offset part - int offset = 0; // set default to '-0000' - bool negOffset = false; - if (parts.count() > 10) { - rx = QRegExp("^([+-])(\\d\\d)(\\d\\d)$"); - if (!parts[10].indexOf(rx)) { - // It's a UTC offset ±hhmm - parts = rx.capturedTexts(); - offset = parts[2].toInt(&ok[0]) * 3600; - int offsetMin = parts[3].toInt(&ok[1]); - if (!ok[0] || !ok[1] || offsetMin > 59) - return QDateTime(); - offset += offsetMin * 60; - negOffset = (parts[1] == QLatin1String("-")); - if (negOffset) - offset = -offset; - } else { - // Check for an obsolete time zone name - QByteArray zone = parts[10].toLatin1(); - if (zone.length() == 1 && isalpha(zone[0]) && toupper(zone[0]) != 'J') - negOffset = true; // military zone: RFC 2822 treats as '-0000' - else if (zone != "UT" && zone != "GMT") { // treated as '+0000' - offset = (zone == "EDT") ? -4*3600 - : (zone == "EST" || zone == "CDT") ? -5*3600 - : (zone == "CST" || zone == "MDT") ? -6*3600 - : (zone == "MST" || zone == "PDT") ? -7*3600 - : (zone == "PST") ? -8*3600 - : 0; - if (!offset) { - // Check for any other alphabetic time zone - bool nonalpha = false; - for (int i = 0, end = zone.size(); i < end && !nonalpha; ++i) - nonalpha = !isalpha(zone[i]); - if (nonalpha) - return QDateTime(); - // TODO: Attempt to recognize the time zone abbreviation? - negOffset = true; // unknown time zone: RFC 2822 treats as '-0000' +// Ported to Qt from KDElibs4 +QDateTime RssParser::parseDate(const QString &string) +{ + const QString str = string.trimmed(); + if (str.isEmpty()) + return QDateTime::currentDateTime(); + + int nyear = 6; // indexes within string to values + int nmonth = 4; + int nday = 2; + int nwday = 1; + int nhour = 7; + int nmin = 8; + int nsec = 9; + // Also accept obsolete form "Weekday, DD-Mon-YY HH:MM:SS ±hhmm" + QRegExp rx("^(?:([A-Z][a-z]+),\\s*)?(\\d{1,2})(\\s+|-)([^-\\s]+)(\\s+|-)(\\d{2,4})\\s+(\\d\\d):(\\d\\d)(?::(\\d\\d))?\\s+(\\S+)$"); + QStringList parts; + if (!str.indexOf(rx)) { + // Check that if date has '-' separators, both separators are '-'. + parts = rx.capturedTexts(); + bool h1 = (parts[3] == QLatin1String("-")); + bool h2 = (parts[5] == QLatin1String("-")); + if (h1 != h2) + return QDateTime::currentDateTime(); + } + else { + // Check for the obsolete form "Wdy Mon DD HH:MM:SS YYYY" + rx = QRegExp("^([A-Z][a-z]+)\\s+(\\S+)\\s+(\\d\\d)\\s+(\\d\\d):(\\d\\d):(\\d\\d)\\s+(\\d\\d\\d\\d)$"); + if (str.indexOf(rx)) + return QDateTime::currentDateTime(); + nyear = 7; + nmonth = 2; + nday = 3; + nwday = 1; + nhour = 4; + nmin = 5; + nsec = 6; + parts = rx.capturedTexts(); + } + + bool ok[4]; + const int day = parts[nday].toInt(&ok[0]); + int year = parts[nyear].toInt(&ok[1]); + const int hour = parts[nhour].toInt(&ok[2]); + const int minute = parts[nmin].toInt(&ok[3]); + if (!ok[0] || !ok[1] || !ok[2] || !ok[3]) + return QDateTime::currentDateTime(); + + int second = 0; + if (!parts[nsec].isEmpty()) { + second = parts[nsec].toInt(&ok[0]); + if (!ok[0]) + return QDateTime::currentDateTime(); + } + + bool leapSecond = (second == 60); + if (leapSecond) + second = 59; // apparently a leap second - validate below, once time zone is known + int month = 0; + for ( ; (month < 12) && (parts[nmonth] != shortMonth[month]); ++month); + int dayOfWeek = -1; + if (!parts[nwday].isEmpty()) { + // Look up the weekday name + while (++dayOfWeek < 7 && (shortDay[dayOfWeek] != parts[nwday])); + if (dayOfWeek >= 7) + for (dayOfWeek = 0; dayOfWeek < 7 && (longDay[dayOfWeek] != parts[nwday]); ++dayOfWeek); + } + + // if (month >= 12 || dayOfWeek >= 7 + // || (dayOfWeek < 0 && format == RFCDateDay)) + // return QDateTime; + int i = parts[nyear].size(); + if (i < 4) { + // It's an obsolete year specification with less than 4 digits + year += (i == 2 && year < 50) ? 2000 : 1900; + } + + // Parse the UTC offset part + int offset = 0; // set default to '-0000' + bool negOffset = false; + if (parts.count() > 10) { + rx = QRegExp("^([+-])(\\d\\d)(\\d\\d)$"); + if (!parts[10].indexOf(rx)) { + // It's a UTC offset ±hhmm + parts = rx.capturedTexts(); + offset = parts[2].toInt(&ok[0]) * 3600; + int offsetMin = parts[3].toInt(&ok[1]); + if (!ok[0] || !ok[1] || offsetMin > 59) + return QDateTime(); + offset += offsetMin * 60; + negOffset = (parts[1] == QLatin1String("-")); + if (negOffset) + offset = -offset; + } + else { + // Check for an obsolete time zone name + QByteArray zone = parts[10].toLatin1(); + if (zone.length() == 1 && isalpha(zone[0]) && toupper(zone[0]) != 'J') { + negOffset = true; // military zone: RFC 2822 treats as '-0000' + } + else if (zone != "UT" && zone != "GMT") { // treated as '+0000' + offset = (zone == "EDT") + ? -4 * 3600 + : ((zone == "EST") || (zone == "CDT")) + ? -5 * 3600 + : ((zone == "CST") || (zone == "MDT")) + ? -6 * 3600 + : (zone == "MST" || zone == "PDT") + ? -7 * 3600 + : (zone == "PST") + ? -8 * 3600 + : 0; + if (!offset) { + // Check for any other alphabetic time zone + bool nonalpha = false; + for (int i = 0, end = zone.size(); (i < end) && !nonalpha; ++i) + nonalpha = !isalpha(zone[i]); + if (nonalpha) + return QDateTime(); + // TODO: Attempt to recognize the time zone abbreviation? + negOffset = true; // unknown time zone: RFC 2822 treats as '-0000' + } + } } - } } - } - QDate qdate(year, month+1, day); // convert date, and check for out-of-range - if (!qdate.isValid()) - return QDateTime::currentDateTime(); - QTime qTime(hour, minute, second); - - QDateTime result(qdate, qTime, Qt::UTC); - if (offset) - result = result.addSecs(-offset); - if (!result.isValid()) - return QDateTime::currentDateTime(); // invalid date/time - - if (leapSecond) { - // Validate a leap second time. Leap seconds are inserted after 23:59:59 UTC. - // Convert the time to UTC and check that it is 00:00:00. - if ((hour*3600 + minute*60 + 60 - offset + 86400*5) % 86400) // (max abs(offset) is 100 hours) - return QDateTime::currentDateTime(); // the time isn't the last second of the day - } - return result; + + QDate qdate(year, month + 1, day); // convert date, and check for out-of-range + if (!qdate.isValid()) + return QDateTime::currentDateTime(); + + QTime qTime(hour, minute, second); + QDateTime result(qdate, qTime, Qt::UTC); + if (offset) + result = result.addSecs(-offset); + if (!result.isValid()) + return QDateTime::currentDateTime(); // invalid date/time + + if (leapSecond) { + // Validate a leap second time. Leap seconds are inserted after 23:59:59 UTC. + // Convert the time to UTC and check that it is 00:00:00. + if ((hour*3600 + minute*60 + 60 - offset + 86400*5) % 86400) // (max abs(offset) is 100 hours) + return QDateTime::currentDateTime(); // the time isn't the last second of the day + } + + return result; } -RssParser::RssParser(QObject *parent) : - QThread(parent), m_running(true) +RssParser::RssParser(QObject *parent) + : QThread(parent) + , m_running(true) { - start(); + start(); } RssParser::~RssParser() { - m_running = false; - m_waitCondition.wakeOne(); - wait(); + m_running = false; + m_waitCondition.wakeOne(); + wait(); } -void RssParser::parseRssFile(const QString& feedUrl, const QString& filePath) +void RssParser::parseRssFile(const QString &feedUrl, const QString &filePath) { - qDebug() << Q_FUNC_INFO << feedUrl << filePath; - m_mutex.lock(); - ParsingJob job = { feedUrl, Utils::Fs::fromNativePath(filePath) }; - m_queue.enqueue(job); - // Wake up thread. - if (m_queue.count() == 1) { - qDebug() << Q_FUNC_INFO << "Waking up thread"; - m_waitCondition.wakeOne(); - } - m_mutex.unlock(); + qDebug() << Q_FUNC_INFO << feedUrl << filePath; + m_mutex.lock(); + ParsingJob job = { feedUrl, Utils::Fs::fromNativePath(filePath) }; + m_queue.enqueue(job); + // Wake up thread. + if (m_queue.count() == 1) { + qDebug() << Q_FUNC_INFO << "Waking up thread"; + m_waitCondition.wakeOne(); + } + m_mutex.unlock(); } void RssParser::clearFeedData(const QString &feedUrl) { - m_mutex.lock(); - m_lastBuildDates.remove(feedUrl); - m_mutex.unlock(); + m_mutex.lock(); + m_lastBuildDates.remove(feedUrl); + m_mutex.unlock(); } void RssParser::run() { - while (m_running) { - m_mutex.lock(); - if (!m_queue.empty()) { - ParsingJob job = m_queue.dequeue(); - m_mutex.unlock(); - parseFeed(job); - } else { - qDebug() << Q_FUNC_INFO << "Thread is waiting."; - m_waitCondition.wait(&m_mutex); - qDebug() << Q_FUNC_INFO << "Thread woke up."; - m_mutex.unlock(); + while (m_running) { + m_mutex.lock(); + if (!m_queue.empty()) { + ParsingJob job = m_queue.dequeue(); + m_mutex.unlock(); + parseFeed(job); + } + else { + qDebug() << Q_FUNC_INFO << "Thread is waiting."; + m_waitCondition.wait(&m_mutex); + qDebug() << Q_FUNC_INFO << "Thread woke up."; + m_mutex.unlock(); + } } - } } -void RssParser::parseRssArticle(QXmlStreamReader& xml, const QString& feedUrl) +void RssParser::parseRssArticle(QXmlStreamReader &xml, const QString &feedUrl) { - QVariantHash article; - - while(!xml.atEnd()) { - xml.readNext(); - - if(xml.isEndElement() && xml.name() == "item") - break; - - if (xml.isStartElement()) { - if (xml.name() == "title") - article["title"] = xml.readElementText().trimmed(); - else if (xml.name() == "enclosure") { - if (xml.attributes().value("type") == "application/x-bittorrent") - article["torrent_url"] = xml.attributes().value("url").toString(); - } - else if (xml.name() == "link") { - QString link = xml.readElementText().trimmed(); - if (link.startsWith("magnet:", Qt::CaseInsensitive)) - article["torrent_url"] = link; // magnet link instead of a news URL - else - article["news_link"] = link; - } - else if (xml.name() == "description") - article["description"] = xml.readElementText().trimmed(); - else if (xml.name() == "pubDate") - article["date"] = parseDate(xml.readElementText().trimmed()); - else if (xml.name() == "author") - article["author"] = xml.readElementText().trimmed(); - else if (xml.name() == "guid") - article["id"] = xml.readElementText().trimmed(); + QVariantHash article; + + while(!xml.atEnd()) { + xml.readNext(); + + if(xml.isEndElement() && xml.name() == "item") + break; + + if (xml.isStartElement()) { + if (xml.name() == "title") { + article["title"] = xml.readElementText().trimmed(); + } + else if (xml.name() == "enclosure") { + if (xml.attributes().value("type") == "application/x-bittorrent") + article["torrent_url"] = xml.attributes().value("url").toString(); + } + else if (xml.name() == "link") { + QString link = xml.readElementText().trimmed(); + if (link.startsWith("magnet:", Qt::CaseInsensitive)) + article["torrent_url"] = link; // magnet link instead of a news URL + else + article["news_link"] = link; + } + else if (xml.name() == "description") { + article["description"] = xml.readElementText().trimmed(); + } + else if (xml.name() == "pubDate") { + article["date"] = parseDate(xml.readElementText().trimmed()); + } + else if (xml.name() == "author") { + article["author"] = xml.readElementText().trimmed(); + } + else if (xml.name() == "guid") { + article["id"] = xml.readElementText().trimmed(); + } + } } - } - if (!article.contains("torrent_url") && article.contains("news_link")) - article["torrent_url"] = article["news_link"]; + if (!article.contains("torrent_url") && article.contains("news_link")) + article["torrent_url"] = article["news_link"]; - if (!article.contains("id")) { - // Item does not have a guid, fall back to some other identifier - const QString link = article.value("news_link").toString(); - if (!link.isEmpty()) - article["id"] = link; - else { - const QString title = article.value("title").toString(); - if (!title.isEmpty()) - article["id"] = title; - else { - qWarning() << "Item has no guid, link or title, ignoring it..."; - return; - } + if (!article.contains("id")) { + // Item does not have a guid, fall back to some other identifier + const QString link = article.value("news_link").toString(); + if (!link.isEmpty()) { + article["id"] = link; + } + else { + const QString title = article.value("title").toString(); + if (!title.isEmpty()) { + article["id"] = title; + } + else { + qWarning() << "Item has no guid, link or title, ignoring it..."; + return; + } + } } - } - emit newArticle(feedUrl, article); + emit newArticle(feedUrl, article); } -void RssParser::parseRSSChannel(QXmlStreamReader& xml, const QString& feedUrl) +void RssParser::parseRSSChannel(QXmlStreamReader &xml, const QString &feedUrl) { - qDebug() << Q_FUNC_INFO << feedUrl; - Q_ASSERT(xml.isStartElement() && xml.name() == "channel"); - - while(!xml.atEnd()) { - xml.readNext(); - - if (xml.isStartElement()) { - if (xml.name() == "title") { - QString title = xml.readElementText(); - emit feedTitle(feedUrl, title); - } - else if (xml.name() == "lastBuildDate") { - QString lastBuildDate = xml.readElementText(); - if (!lastBuildDate.isEmpty()) { - QMutexLocker locker(&m_mutex); - if (m_lastBuildDates.value(feedUrl, "") == lastBuildDate) { - qDebug() << "The RSS feed has not changed since last time, aborting parsing."; - return; - } - m_lastBuildDates[feedUrl] = lastBuildDate; + qDebug() << Q_FUNC_INFO << feedUrl; + Q_ASSERT(xml.isStartElement() && xml.name() == "channel"); + + while(!xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement()) { + if (xml.name() == "title") { + QString title = xml.readElementText(); + emit feedTitle(feedUrl, title); + } + else if (xml.name() == "lastBuildDate") { + QString lastBuildDate = xml.readElementText(); + if (!lastBuildDate.isEmpty()) { + QMutexLocker locker(&m_mutex); + if (m_lastBuildDates.value(feedUrl, "") == lastBuildDate) { + qDebug() << "The RSS feed has not changed since last time, aborting parsing."; + return; + } + m_lastBuildDates[feedUrl] = lastBuildDate; + } + } + else if (xml.name() == "item") { + parseRssArticle(xml, feedUrl); + } } - } - else if (xml.name() == "item") { - parseRssArticle(xml, feedUrl); - } } - } } -void RssParser::parseAtomArticle(QXmlStreamReader& xml, const QString& feedUrl, const QString& baseUrl) +void RssParser::parseAtomArticle(QXmlStreamReader &xml, const QString &feedUrl, const QString &baseUrl) { - QVariantHash article; - bool double_content = false; - - while(!xml.atEnd()) { - xml.readNext(); - - if(xml.isEndElement() && xml.name() == "entry") - break; - - if (xml.isStartElement()) { - if (xml.name() == "title") { - article["title"] = xml.readElementText().trimmed(); - } - else if (xml.name() == "link") { - QString link = ( xml.attributes().isEmpty() ? - xml.readElementText().trimmed() : - xml.attributes().value("href").toString() ); - - if (link.startsWith("magnet:", Qt::CaseInsensitive)) - article["torrent_url"] = link; // magnet link instead of a news URL - else - // Atom feeds can have relative links, work around this and - // take the stress of figuring article full URI from UI - // Assemble full URI - article["news_link"] = ( baseUrl.isEmpty() ? link : baseUrl + link ); - - } - else if (xml.name() == "summary" || xml.name() == "content"){ - if(double_content) { // Duplicate content -> ignore - xml.readNext(); - - while(xml.name() != "summary" && xml.name() != "content") - xml.readNext(); - - continue; - } + QVariantHash article; + bool doubleContent = false; - // Try to also parse broken articles, which don't use html '&' escapes - // Actually works great for non-broken content too - QString feedText = xml.readElementText(QXmlStreamReader::IncludeChildElements); - if (!feedText.isEmpty()) - article["description"] = feedText.trimmed(); - - double_content = true; - } - else if (xml.name() == "updated"){ - // ATOM uses standard compliant date, don't do fancy stuff - QDateTime articleDate = QDateTime::fromString(xml.readElementText().trimmed(), Qt::ISODate); - article["date"] = ( articleDate.isValid() ? - articleDate : - QDateTime::currentDateTime() ); - } - else if (xml.name() == "author") { + while(!xml.atEnd()) { xml.readNext(); - while(xml.name() != "author") { - if(xml.name() == "name") - article["author"] = xml.readElementText().trimmed(); - xml.readNext(); + + if(xml.isEndElement() && (xml.name() == "entry")) + break; + + if (xml.isStartElement()) { + if (xml.name() == "title") { + article["title"] = xml.readElementText().trimmed(); + } + else if (xml.name() == "link") { + QString link = ( xml.attributes().isEmpty() ? + xml.readElementText().trimmed() : + xml.attributes().value("href").toString() ); + + if (link.startsWith("magnet:", Qt::CaseInsensitive)) + article["torrent_url"] = link; // magnet link instead of a news URL + else + // Atom feeds can have relative links, work around this and + // take the stress of figuring article full URI from UI + // Assemble full URI + article["news_link"] = ( baseUrl.isEmpty() ? link : baseUrl + link ); + + } + else if ((xml.name() == "summary") || (xml.name() == "content")){ + if (doubleContent) { // Duplicate content -> ignore + xml.readNext(); + + while ((xml.name() != "summary") && (xml.name() != "content")) + xml.readNext(); + + continue; + } + + // Try to also parse broken articles, which don't use html '&' escapes + // Actually works great for non-broken content too + QString feedText = xml.readElementText(QXmlStreamReader::IncludeChildElements); + if (!feedText.isEmpty()) + article["description"] = feedText.trimmed(); + + doubleContent = true; + } + else if (xml.name() == "updated") { + // ATOM uses standard compliant date, don't do fancy stuff + QDateTime articleDate = QDateTime::fromString(xml.readElementText().trimmed(), Qt::ISODate); + article["date"] = (articleDate.isValid() ? articleDate : QDateTime::currentDateTime()); + } + else if (xml.name() == "author") { + xml.readNext(); + while(xml.name() != "author") { + if(xml.name() == "name") + article["author"] = xml.readElementText().trimmed(); + xml.readNext(); + } + } + else if (xml.name() == "id") { + article["id"] = xml.readElementText().trimmed(); + } } - } - else if (xml.name() == "id") - article["id"] = xml.readElementText().trimmed(); } - } - if (!article.contains("torrent_url") && article.contains("news_link")) - article["torrent_url"] = article["news_link"]; + if (!article.contains("torrent_url") && article.contains("news_link")) + article["torrent_url"] = article["news_link"]; - if (!article.contains("id")) { - // Item does not have a guid, fall back to some other identifier - const QString link = article.value("news_link").toString(); - if (!link.isEmpty()) - article["id"] = link; - else { - const QString title = article.value("title").toString(); - if (!title.isEmpty()) - article["id"] = title; - else { - qWarning() << "Item has no guid, link or title, ignoring it..."; - return; - } + if (!article.contains("id")) { + // Item does not have a guid, fall back to some other identifier + const QString link = article.value("news_link").toString(); + if (!link.isEmpty()) { + article["id"] = link; + } + else { + const QString title = article.value("title").toString(); + if (!title.isEmpty()) { + article["id"] = title; + } + else { + qWarning() << "Item has no guid, link or title, ignoring it..."; + return; + } + } } - } - emit newArticle(feedUrl, article); + emit newArticle(feedUrl, article); } -void RssParser::parseAtomChannel(QXmlStreamReader& xml, const QString& feedUrl) +void RssParser::parseAtomChannel(QXmlStreamReader &xml, const QString &feedUrl) { - qDebug() << Q_FUNC_INFO << feedUrl; - Q_ASSERT(xml.isStartElement() && xml.name() == "feed"); - - QString baseURL = xml.attributes().value("xml:base").toString(); - - while(!xml.atEnd()) { - xml.readNext(); - - if (xml.isStartElement()) { - if (xml.name() == "title") { - QString title = xml.readElementText(); - emit feedTitle(feedUrl, title); - } - else if (xml.name() == "updated") { - QString lastBuildDate = xml.readElementText(); - if (!lastBuildDate.isEmpty()) { - QMutexLocker locker(&m_mutex); - if (m_lastBuildDates.value(feedUrl) == lastBuildDate) { - qDebug() << "The RSS feed has not changed since last time, aborting parsing."; - return; - } - m_lastBuildDates[feedUrl] = lastBuildDate; + qDebug() << Q_FUNC_INFO << feedUrl; + Q_ASSERT(xml.isStartElement() && xml.name() == "feed"); + + QString baseURL = xml.attributes().value("xml:base").toString(); + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement()) { + if (xml.name() == "title") { + QString title = xml.readElementText(); + emit feedTitle(feedUrl, title); + } + else if (xml.name() == "updated") { + QString lastBuildDate = xml.readElementText(); + if (!lastBuildDate.isEmpty()) { + QMutexLocker locker(&m_mutex); + if (m_lastBuildDates.value(feedUrl) == lastBuildDate) { + qDebug() << "The RSS feed has not changed since last time, aborting parsing."; + return; + } + m_lastBuildDates[feedUrl] = lastBuildDate; + } + } + else if (xml.name() == "entry") { + parseAtomArticle(xml, feedUrl, baseURL); + } } - } - else if (xml.name() == "entry") { - parseAtomArticle(xml, feedUrl, baseURL); - } } - } } // read and create items from a rss document -void RssParser::parseFeed(const ParsingJob& job) +void RssParser::parseFeed(const ParsingJob &job) { - qDebug() << Q_FUNC_INFO << job.feedUrl << job.filePath; - QFile fileRss(job.filePath); - if (!fileRss.open(QIODevice::ReadOnly | QIODevice::Text)) { - reportFailure(job, tr("Failed to open downloaded RSS file.")); - return; - } - QXmlStreamReader xml(&fileRss); - - bool found_channel = false; - while (xml.readNextStartElement()) { - if (xml.name() == "rss") { - // Find channels - while (xml.readNextStartElement()) { - if (xml.name() == "channel") { - parseRSSChannel(xml, job.feedUrl); - found_channel = true; - break; - } else { - qDebug() << "Skip rss item: " << xml.name(); - xml.skipCurrentElement(); + qDebug() << Q_FUNC_INFO << job.feedUrl << job.filePath; + QFile fileRss(job.filePath); + if (!fileRss.open(QIODevice::ReadOnly | QIODevice::Text)) { + reportFailure(job, tr("Failed to open downloaded RSS file.")); + return; + } + + QXmlStreamReader xml(&fileRss); + bool foundChannel = false; + while (xml.readNextStartElement()) { + if (xml.name() == "rss") { + // Find channels + while (xml.readNextStartElement()) { + if (xml.name() == "channel") { + parseRSSChannel(xml, job.feedUrl); + foundChannel = true; + break; + } + else { + qDebug() << "Skip rss item: " << xml.name(); + xml.skipCurrentElement(); + } + } + break; + } + else if (xml.name() == "feed") { // Atom feed + parseAtomChannel(xml, job.feedUrl); + foundChannel = true; + break; + } + else { + qDebug() << "Skip root item: " << xml.name(); + xml.skipCurrentElement(); } - } - break; } - else if (xml.name() == "feed") { // Atom feed - parseAtomChannel(xml, job.feedUrl); - found_channel = true; - break; - } else { - qDebug() << "Skip root item: " << xml.name(); - xml.skipCurrentElement(); + + if (xml.hasError()) { + reportFailure(job, xml.errorString()); + return; } - } - - if (xml.hasError()) { - reportFailure(job, xml.errorString()); - return; - } - - if (!found_channel) { - reportFailure(job, tr("Invalid RSS feed at '%1'.").arg(job.feedUrl)); - return; - } - - // Clean up - fileRss.close(); - emit feedParsingFinished(job.feedUrl, QString()); - Utils::Fs::forceRemove(job.filePath); + + if (!foundChannel) { + reportFailure(job, tr("Invalid RSS feed at '%1'.").arg(job.feedUrl)); + return; + } + + // Clean up + fileRss.close(); + emit feedParsingFinished(job.feedUrl, QString()); + Utils::Fs::forceRemove(job.filePath); } -void RssParser::reportFailure(const ParsingJob& job, const QString& error) +void RssParser::reportFailure(const ParsingJob &job, const QString &error) { - emit feedParsingFinished(job.feedUrl, error); - Utils::Fs::forceRemove(job.filePath); + emit feedParsingFinished(job.feedUrl, error); + Utils::Fs::forceRemove(job.filePath); } diff --git a/src/base/rss/rssparser.h b/src/base/rss/rssparser.h index 23608127b..42b52d9bb 100644 --- a/src/base/rss/rssparser.h +++ b/src/base/rss/rssparser.h @@ -1,5 +1,5 @@ /* - * Bittorrent Client using Qt4 and libtorrent. + * Bittorrent Client using Qt and libtorrent. * Copyright (C) 2012 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -40,39 +40,40 @@ struct ParsingJob; -class RssParser : public QThread +class RssParser: public QThread { - Q_OBJECT + Q_OBJECT public: - explicit RssParser(QObject *parent = 0); - virtual ~RssParser(); + explicit RssParser(QObject *parent = 0); + virtual ~RssParser(); signals: - void newArticle(const QString& feedUrl, const QVariantHash& rssArticle); - void feedTitle(const QString& feedUrl, const QString& title); - void feedParsingFinished(const QString& feedUrl, const QString& error); + void newArticle(const QString &feedUrl, const QVariantHash &rssArticle); + void feedTitle(const QString &feedUrl, const QString &title); + void feedParsingFinished(const QString &feedUrl, const QString &error); public slots: - void parseRssFile(const QString& feedUrl, const QString& filePath); - void clearFeedData(const QString& feedUrl); + void parseRssFile(const QString &feedUrl, const QString &filePath); + void clearFeedData(const QString &feedUrl); protected: - virtual void run(); - static QDateTime parseDate(const QString& string); - void parseRssArticle(QXmlStreamReader& xml, const QString& feedUrl); - void parseRSSChannel(QXmlStreamReader& xml, const QString& feedUrl); - void parseAtomArticle(QXmlStreamReader& xml, const QString& feedUrl, const QString& baseUrl); - void parseAtomChannel(QXmlStreamReader& xml, const QString& feedUrl); - void parseFeed(const ParsingJob& job); - void reportFailure(const ParsingJob& job, const QString& error); + virtual void run(); private: - bool m_running; - QMutex m_mutex; - QQueue m_queue; - QWaitCondition m_waitCondition; - QHash m_lastBuildDates; // Optimization + static QDateTime parseDate(const QString &string); + void parseRssArticle(QXmlStreamReader &xml, const QString &feedUrl); + void parseRSSChannel(QXmlStreamReader &xml, const QString &feedUrl); + void parseAtomArticle(QXmlStreamReader &xml, const QString &feedUrl, const QString &baseUrl); + void parseAtomChannel(QXmlStreamReader &xml, const QString &feedUrl); + void parseFeed(const ParsingJob &job); + void reportFailure(const ParsingJob &job, const QString &error); + + bool m_running; + QMutex m_mutex; + QQueue m_queue; + QWaitCondition m_waitCondition; + QHash m_lastBuildDates; // Optimization }; #endif // RSSPARSER_H diff --git a/src/gui/rss/feedlistwidget.cpp b/src/gui/rss/feedlistwidget.cpp index 9c30274f0..4bf2b2129 100644 --- a/src/gui/rss/feedlistwidget.cpp +++ b/src/gui/rss/feedlistwidget.cpp @@ -28,8 +28,8 @@ * Contact: chris@qbittorrent.org, arnaud@qbittorrent.org */ -#include "core/rss/rssmanager.h" -#include "core/rss/rssfeed.h" +#include "base/rss/rssmanager.h" +#include "base/rss/rssfeed.h" #include "guiiconprovider.h" #include "feedlistwidget.h"