mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-19 06:57:24 -06:00
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015, 2017 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2015-2022 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2010 Christophe Dumez <chris@qbittorrent.org>
|
||||
* Copyright (C) 2010 Arnaud Demaiziere <arnaud@qbittorrent.org>
|
||||
*
|
||||
@@ -34,12 +34,12 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <QDir>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QUrl>
|
||||
#include <QVector>
|
||||
|
||||
#include "base/asyncfilestorage.h"
|
||||
#include "base/global.h"
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/profile.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "feed_serializer.h"
|
||||
#include "rss_article.h"
|
||||
#include "rss_parser.h"
|
||||
#include "rss_session.h"
|
||||
@@ -79,6 +80,11 @@ Feed::Feed(const QUuid &uid, const QString &url, const QString &path, Session *s
|
||||
|
||||
m_iconPath = storageDir / Path(uidHex + u".ico");
|
||||
|
||||
m_serializer = new Private::FeedSerializer;
|
||||
m_serializer->moveToThread(m_session->workingThread());
|
||||
connect(this, &Feed::destroyed, m_serializer, &Private::FeedSerializer::deleteLater);
|
||||
connect(m_serializer, &Private::FeedSerializer::loadingFinished, this, &Feed::handleArticleLoadFinished);
|
||||
|
||||
m_parser = new Private::Parser(m_lastBuildDate);
|
||||
m_parser->moveToThread(m_session->workingThread());
|
||||
connect(this, &Feed::destroyed, m_parser, &Private::Parser::deleteLater);
|
||||
@@ -98,6 +104,7 @@ Feed::Feed(const QUuid &uid, const QString &url, const QString &path, Session *s
|
||||
|
||||
Feed::~Feed()
|
||||
{
|
||||
store();
|
||||
emit aboutToBeDestroyed(this);
|
||||
}
|
||||
|
||||
@@ -130,6 +137,12 @@ void Feed::markAsRead()
|
||||
|
||||
void Feed::refresh()
|
||||
{
|
||||
if (!m_isInitialized)
|
||||
{
|
||||
m_pendingRefresh = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_downloadHandler)
|
||||
m_downloadHandler->cancel();
|
||||
|
||||
@@ -162,7 +175,7 @@ QString Feed::title() const
|
||||
|
||||
bool Feed::isLoading() const
|
||||
{
|
||||
return m_isLoading;
|
||||
return m_isLoading || !m_isInitialized;
|
||||
}
|
||||
|
||||
QString Feed::lastBuildDate() const
|
||||
@@ -261,100 +274,30 @@ void Feed::handleParsingFinished(const RSS::Private::ParsingResult &result)
|
||||
|
||||
void Feed::load()
|
||||
{
|
||||
QFile file {(m_session->dataFileStorage()->storageDir() / m_dataFileName).data()};
|
||||
|
||||
if (!file.exists())
|
||||
QMetaObject::invokeMethod(m_serializer, [this]()
|
||||
{
|
||||
loadArticlesLegacy();
|
||||
m_dirty = true;
|
||||
store(); // convert to new format
|
||||
}
|
||||
else if (file.open(QFile::ReadOnly))
|
||||
{
|
||||
loadArticles(file.readAll());
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMsg(tr("Couldn't read RSS Session data from %1. Error: %2")
|
||||
.arg(m_dataFileName.toString(), file.errorString())
|
||||
, Log::WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
void Feed::loadArticles(const QByteArray &data)
|
||||
{
|
||||
QJsonParseError jsonError;
|
||||
const QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||
if (jsonError.error != QJsonParseError::NoError)
|
||||
{
|
||||
LogMsg(tr("Couldn't parse RSS Session data. Error: %1").arg(jsonError.errorString())
|
||||
, Log::WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!jsonDoc.isArray())
|
||||
{
|
||||
LogMsg(tr("Couldn't load RSS Session data. Invalid data format."), Log::WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonArray jsonArr = jsonDoc.array();
|
||||
int i = -1;
|
||||
for (const QJsonValue &jsonVal : jsonArr)
|
||||
{
|
||||
++i;
|
||||
if (!jsonVal.isObject())
|
||||
{
|
||||
LogMsg(tr("Couldn't load RSS article '%1#%2'. Invalid data format.").arg(m_url).arg(i)
|
||||
, Log::WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto article = new Article(this, jsonVal.toObject());
|
||||
if (!addArticle(article))
|
||||
delete article;
|
||||
}
|
||||
catch (const RuntimeError &) {}
|
||||
}
|
||||
}
|
||||
|
||||
void Feed::loadArticlesLegacy()
|
||||
{
|
||||
const SettingsPtr qBTRSSFeeds = Profile::instance()->applicationSettings(u"qBittorrent-rss-feeds"_qs);
|
||||
const QVariantHash allOldItems = qBTRSSFeeds->value(u"old_items"_qs).toHash();
|
||||
|
||||
for (const QVariant &var : asConst(allOldItems.value(m_url).toList()))
|
||||
{
|
||||
auto hash = var.toHash();
|
||||
// update legacy keys
|
||||
hash[Article::KeyLink] = hash.take(u"news_link"_qs);
|
||||
hash[Article::KeyTorrentURL] = hash.take(u"torrent_url"_qs);
|
||||
hash[Article::KeyIsRead] = hash.take(u"read"_qs);
|
||||
try
|
||||
{
|
||||
auto article = new Article(this, hash);
|
||||
if (!addArticle(article))
|
||||
delete article;
|
||||
}
|
||||
catch (const RuntimeError &) {}
|
||||
}
|
||||
m_serializer->load((m_session->dataFileStorage()->storageDir() / m_dataFileName), m_url);
|
||||
});
|
||||
}
|
||||
|
||||
void Feed::store()
|
||||
{
|
||||
if (!m_dirty) return;
|
||||
if (!m_dirty)
|
||||
return;
|
||||
|
||||
m_dirty = false;
|
||||
m_savingTimer.stop();
|
||||
|
||||
QJsonArray jsonArr;
|
||||
for (Article *article :asConst(m_articles))
|
||||
jsonArr << article->toJsonObject();
|
||||
QVector<QVariantHash> articlesData;
|
||||
articlesData.reserve(m_articles.size());
|
||||
|
||||
m_session->dataFileStorage()->store(m_dataFileName, QJsonDocument(jsonArr).toJson());
|
||||
for (Article *article :asConst(m_articles))
|
||||
articlesData.push_back(article->data());
|
||||
|
||||
QMetaObject::invokeMethod(m_serializer, [this, articlesData]()
|
||||
{
|
||||
m_serializer->store((m_session->dataFileStorage()->storageDir() / m_dataFileName), articlesData);
|
||||
});
|
||||
}
|
||||
|
||||
void Feed::storeDeferred()
|
||||
@@ -546,8 +489,33 @@ void Feed::handleArticleRead(Article *article)
|
||||
storeDeferred();
|
||||
}
|
||||
|
||||
void Feed::handleArticleLoadFinished(const QVector<QVariantHash> &articles)
|
||||
{
|
||||
for (const QVariantHash &data : articles)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto *article = new Article(this, data);
|
||||
if (!addArticle(article))
|
||||
delete article;
|
||||
}
|
||||
catch (const RuntimeError &) {}
|
||||
}
|
||||
|
||||
m_isInitialized = true;
|
||||
emit stateChanged(this);
|
||||
|
||||
if (m_pendingRefresh)
|
||||
{
|
||||
m_pendingRefresh = false;
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Feed::cleanup()
|
||||
{
|
||||
m_dirty = false;
|
||||
m_savingTimer.stop();
|
||||
Utils::Fs::removeFile(m_session->dataFileStorage()->storageDir() / m_dataFileName);
|
||||
Utils::Fs::removeFile(m_iconPath);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user