From 475348595cb9a2e25cbbf3b0d646879bc76680bb Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Sun, 28 May 2017 13:59:26 +0300 Subject: [PATCH] Improve RSS::Article class Store more RSS article fields. Don't use legacy article field names in Parser code. --- src/base/rss/private/rss_parser.cpp | 10 +-- src/base/rss/rss_article.cpp | 103 +++++++++++----------------- src/base/rss/rss_article.h | 9 +-- src/base/rss/rss_feed.cpp | 28 +++++--- 4 files changed, 69 insertions(+), 81 deletions(-) diff --git a/src/base/rss/private/rss_parser.cpp b/src/base/rss/private/rss_parser.cpp index 5356c8dd3..24dd9f1d0 100644 --- a/src/base/rss/private/rss_parser.cpp +++ b/src/base/rss/private/rss_parser.cpp @@ -294,13 +294,13 @@ void Parser::parseRssArticle(QXmlStreamReader &xml) } else if (name == "enclosure") { if (xml.attributes().value("type") == "application/x-bittorrent") - article["torrent_url"] = xml.attributes().value("url").toString(); + article["torrentURL"] = xml.attributes().value("url").toString(); } else if (name == "link") { if (text.startsWith("magnet:", Qt::CaseInsensitive)) - article["torrent_url"] = text; // magnet link instead of a news URL + article["torrentURL"] = text; // magnet link instead of a news URL else - article["news_link"] = text; + article["link"] = text; } else if (name == "description") { article["description"] = text; @@ -374,12 +374,12 @@ void Parser::parseAtomArticle(QXmlStreamReader &xml) : xml.attributes().value("href").toString()); if (link.startsWith("magnet:", Qt::CaseInsensitive)) - article["torrent_url"] = link; // magnet link instead of a news URL + article["torrentURL"] = 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"] = (m_baseUrl.isEmpty() ? link : m_baseUrl + link); + article["link"] = (m_baseUrl.isEmpty() ? link : m_baseUrl + link); } else if ((name == "summary") || (name == "content")){ diff --git a/src/base/rss/rss_article.cpp b/src/base/rss/rss_article.cpp index 8fe99ea22..c4bfe7b8f 100644 --- a/src/base/rss/rss_article.cpp +++ b/src/base/rss/rss_article.cpp @@ -30,6 +30,7 @@ #include "rss_article.h" +#include #include #include @@ -41,27 +42,41 @@ const QString Str_Title(QStringLiteral("title")); const QString Str_Author(QStringLiteral("author")); const QString Str_Description(QStringLiteral("description")); const QString Str_TorrentURL(QStringLiteral("torrentURL")); -const QString Str_Torrent_Url(QStringLiteral("torrent_url")); const QString Str_Link(QStringLiteral("link")); -const QString Str_News_Link(QStringLiteral("news_link")); const QString Str_IsRead(QStringLiteral("isRead")); -const QString Str_Read(QStringLiteral("read")); using namespace RSS; -Article::Article(Feed *feed, QString guid, QDateTime date, QString title, QString author - , QString description, QString torrentUrl, QString link, bool isRead) +Article::Article(Feed *feed, const QVariantHash &varHash) : QObject(feed) , m_feed(feed) - , m_guid(guid) - , m_date(date) - , m_title(title) - , m_author(author) - , m_description(description) - , m_torrentURL(torrentUrl) - , m_link(link) - , m_isRead(isRead) + , m_guid(varHash.value(Str_Id).toString()) + , m_date(varHash.value(Str_Date).toDateTime()) + , m_title(varHash.value(Str_Title).toString()) + , m_author(varHash.value(Str_Author).toString()) + , m_description(varHash.value(Str_Description).toString()) + , m_torrentURL(varHash.value(Str_TorrentURL).toString()) + , m_link(varHash.value(Str_Link).toString()) + , m_isRead(varHash.value(Str_IsRead, false).toBool()) + , m_data(varHash) { + // If item does not have a guid, fall back to some other identifier + if (m_guid.isEmpty()) + m_guid = varHash.value(Str_TorrentURL).toString(); + if (m_guid.isEmpty()) + m_guid = varHash.value(Str_Title).toString(); + if (m_guid.isEmpty()) + throw std::runtime_error("Bad RSS Article data"); + + m_data[Str_Id] = m_guid; +} + +Article::Article(Feed *feed, const QJsonObject &jsonObj) + : Article(feed, jsonObj.toVariantHash()) +{ + // JSON object store DateTime as string so we need to convert it + m_date = QDateTime::fromString(jsonObj.value(Str_Date).toString(), Qt::RFC2822Date); + m_data[Str_Date] = m_date; } QString Article::guid() const @@ -104,26 +119,27 @@ bool Article::isRead() const return m_isRead; } +QVariantHash Article::data() const +{ + return m_data; +} + void Article::markAsRead() { if (!m_isRead) { m_isRead = true; + m_data[Str_IsRead] = m_isRead; emit read(this); } } QJsonObject Article::toJsonObject() const { - return { - {Str_Id, m_guid}, - {Str_Date, m_date.toString(Qt::RFC2822Date)}, - {Str_Title, m_title}, - {Str_Author, m_author}, - {Str_Description, m_description}, - {Str_TorrentURL, m_torrentURL}, - {Str_Link, m_link}, - {Str_IsRead, m_isRead} - }; + auto jsonObj = QJsonObject::fromVariantHash(m_data); + // JSON object doesn't support DateTime so we need to convert it + jsonObj[Str_Date] = m_date.toString(Qt::RFC2822Date); + + return jsonObj; } bool Article::articleDateRecentThan(Article *article, const QDateTime &date) @@ -131,47 +147,6 @@ bool Article::articleDateRecentThan(Article *article, const QDateTime &date) return article->date() > date; } -Article *Article::fromJsonObject(Feed *feed, const QJsonObject &jsonObj) -{ - QString guid = jsonObj.value(Str_Id).toString(); - // If item does not have a guid, fall back to some other identifier - if (guid.isEmpty()) - guid = jsonObj.value(Str_Torrent_Url).toString(); - if (guid.isEmpty()) - guid = jsonObj.value(Str_Title).toString(); - if (guid.isEmpty()) return nullptr; - - return new Article( - feed, guid - , QDateTime::fromString(jsonObj.value(Str_Date).toString(), Qt::RFC2822Date) - , jsonObj.value(Str_Title).toString() - , jsonObj.value(Str_Author).toString() - , jsonObj.value(Str_Description).toString() - , jsonObj.value(Str_TorrentURL).toString() - , jsonObj.value(Str_Link).toString() - , jsonObj.value(Str_IsRead).toBool(false)); -} - -Article *Article::fromVariantHash(Feed *feed, const QVariantHash &varHash) -{ - QString guid = varHash[Str_Id].toString(); - // If item does not have a guid, fall back to some other identifier - if (guid.isEmpty()) - guid = varHash.value(Str_Torrent_Url).toString(); - if (guid.isEmpty()) - guid = varHash.value(Str_Title).toString(); - if (guid.isEmpty()) return nullptr; - - return new Article(feed, guid - , varHash.value(Str_Date).toDateTime() - , varHash.value(Str_Title).toString() - , varHash.value(Str_Author).toString() - , varHash.value(Str_Description).toString() - , varHash.value(Str_Torrent_Url).toString() - , varHash.value(Str_News_Link).toString() - , varHash.value(Str_Read, false).toBool()); -} - Feed *Article::feed() const { return m_feed; diff --git a/src/base/rss/rss_article.h b/src/base/rss/rss_article.h index d4fc0bbdf..6a9970f88 100644 --- a/src/base/rss/rss_article.h +++ b/src/base/rss/rss_article.h @@ -33,6 +33,7 @@ #include #include #include +#include namespace RSS { @@ -45,10 +46,8 @@ namespace RSS friend class Feed; - Article(Feed *feed, QString guid, QDateTime date, QString title, QString author - , QString description, QString torrentUrl, QString link, bool isRead = false); - static Article *fromJsonObject(Feed *feed, const QJsonObject &jsonObj); - static Article *fromVariantHash(Feed *feed, const QVariantHash &varHash); + Article(Feed *feed, const QVariantHash &varHash); + Article(Feed *feed, const QJsonObject &jsonObj); public: Feed *feed() const; @@ -60,6 +59,7 @@ namespace RSS QString torrentUrl() const; QString link() const; bool isRead() const; + QVariantHash data() const; void markAsRead(); @@ -80,5 +80,6 @@ namespace RSS QString m_torrentURL; QString m_link; bool m_isRead = false; + QVariantHash m_data; }; } diff --git a/src/base/rss/rss_feed.cpp b/src/base/rss/rss_feed.cpp index 3d1099063..917be225d 100644 --- a/src/base/rss/rss_feed.cpp +++ b/src/base/rss/rss_feed.cpp @@ -207,13 +207,14 @@ void Feed::handleParsingFinished(const RSS::Private::ParsingResult &result) m_lastBuildDate = result.lastBuildDate; foreach (const QVariantHash &varHash, result.articles) { - auto article = Article::fromVariantHash(this, varHash); - if (article) { + try { + auto article = new Article(this, varHash); if (!addArticle(article)) delete article; else m_dirty = true; } + catch (const std::runtime_error&) {} } store(); @@ -272,9 +273,12 @@ void Feed::loadArticles(const QByteArray &data) continue; } - auto article = Article::fromJsonObject(this, jsonVal.toObject()); - if (article && !addArticle(article)) - delete article; + try { + auto article = new Article(this, jsonVal.toObject()); + if (!addArticle(article)) + delete article; + } + catch (const std::runtime_error&) {} } } @@ -284,9 +288,17 @@ void Feed::loadArticlesLegacy() QVariantHash allOldItems = qBTRSSFeeds->value("old_items").toHash(); foreach (const QVariant &var, allOldItems.value(m_url).toList()) { - auto article = Article::fromVariantHash(this, var.toHash()); - if (article && !addArticle(article)) - delete article; + auto hash = var.toHash(); + // update legacy keys + hash[QLatin1String("link")] = hash.take(QLatin1String("news_link")); + hash[QLatin1String("torrentURL")] = hash.take(QLatin1String("torrent_url")); + hash[QLatin1String("isRead")] = hash.take(QLatin1String("read")); + try { + auto article = new Article(this, hash); + if (!addArticle(article)) + delete article; + } + catch (const std::runtime_error&) {} } }