31 #include <QDataStream>
33 #include <QJsonDocument>
34 #include <QJsonObject>
42 #include "../bittorrent/magneturi.h"
43 #include "../bittorrent/session.h"
44 #include "../asyncfilestorage.h"
45 #include "../global.h"
46 #include "../logger.h"
47 #include "../profile.h"
48 #include "../utils/fs.h"
66 QVector<RSS::AutoDownloadRule>
rulesFromJSON(
const QByteArray &jsonData)
68 QJsonParseError jsonError;
69 const QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &jsonError);
70 if (jsonError.error != QJsonParseError::NoError)
73 if (!jsonDoc.isObject())
76 const QJsonObject jsonObj {jsonDoc.object()};
77 QVector<RSS::AutoDownloadRule> rules;
78 for (
auto it = jsonObj.begin(); it != jsonObj.end(); ++it)
80 const QJsonValue jsonVal {it.value()};
81 if (!jsonVal.isObject())
97 return QString::fromLatin1(
"(?:_|\\b)(?:%1)(?:_|\\b)").arg(filters.join(QString(
")|(?:")));
101 : m_storeProcessingEnabled(
"RSS/AutoDownloader/EnableProcessing", false)
102 , m_storeSmartEpisodeFilter(
"RSS/AutoDownloader/SmartEpisodeFilter")
103 , m_storeDownloadRepacks(
"RSS/AutoDownloader/DownloadRepacks")
104 , m_processingTimer(new QTimer(this))
105 , m_ioThread(new QThread(this))
113 throw RuntimeError(tr(
"Directory for RSS AutoDownloader data is unavailable."));
119 LogMsg(tr(
"Couldn't save RSS AutoDownloader data in %1. Error: %2")
133 QRegularExpression::CaseInsensitiveOption
134 | QRegularExpression::ExtendedPatternSyntaxOption
135 | QRegularExpression::UseUnicodePropertiesOption);
161 return m_rules.contains(ruleName);
198 if (!
hasRule(ruleName))
return false;
199 if (
hasRule(newRuleName))
return false;
203 m_rules.insert(newRuleName, rule);
212 if (
m_rules.contains(ruleName))
248 jsonObj.insert(rule.name(), rule.toJsonObject());
250 return QJsonDocument(jsonObj).toJson();
263 dict[rule.name()] = rule.toLegacyDict();
266 QDataStream out(&data, QIODevice::WriteOnly);
267 out.setVersion(QDataStream::Qt_4_5);
275 QDataStream in(data);
276 in.setVersion(QDataStream::Qt_4_5);
279 if (in.status() != QDataStream::Ok)
282 for (
const QVariant &val :
asConst(dict))
291 const QStringList defaultFilters =
295 "(\\d{4}[.\\-]\\d{1,2}[.\\-]\\d{1,2})",
296 "(\\d{1,2}[.\\-]\\d{1,2}[.\\-]\\d{4})"
298 return defaultFilters;
300 return filter.toStringList();
343 article->markAsRead();
365 const QString torrentURL = article->
torrentUrl();
369 job->feedURL = article->
feed()->
url();
370 job->articleData = article->
data();
380 if (!rule.isEnabled())
continue;
381 if (!rule.feedURLs().contains(job->feedURL))
continue;
382 if (!rule.accepts(job->articleData))
continue;
389 params.
category = rule.assignedCategory();
392 if (!rule.savePath().isEmpty())
402 article->markAsRead();
419 if (!rulesFile.exists())
421 else if (rulesFile.open(QFile::ReadOnly))
424 LogMsg(tr(
"Couldn't read RSS AutoDownloader rules from %1. Error: %2")
425 .arg(rulesFile.fileName(), rulesFile.errorString()),
Log::CRITICAL);
433 for (
const auto &rule :
rules)
438 LogMsg(tr(
"Couldn't load RSS AutoDownloader rules. Reason: %1")
446 const QVariantHash
rules =
settings->value(QStringLiteral(
"download_rules")).toHash();
447 for (
const QVariant &ruleVar :
rules)
450 if (!rule.name().isEmpty())
464 jsonObj.insert(rule.name(), rule.toJsonObject());
487 if (!article->isRead() && !article->torrentUrl().isEmpty())
void failed(const QString &fileName, const QString &errorString)
void store(const QString &fileName, const QByteArray &data)
static Session * instance()
void downloadFromUrlFinished(const QString &url)
bool addTorrent(const QString &source, const AddTorrentParams ¶ms=AddTorrentParams())
void downloadFromUrlFailed(const QString &url, const QString &reason)
QString message() const noexcept
SettingsPtr applicationSettings(const QString &name) const
static const Profile * instance()
QString torrentUrl() const
static const QString KeyId
static const QString KeyTorrentURL
QVariantHash data() const
static AutoDownloadRule fromJsonObject(const QJsonObject &jsonObj, const QString &name="")
static AutoDownloadRule fromLegacyDict(const QVariantHash &dict)
void setName(const QString &name)
QByteArray exportRulesToJSONFormat() const
void importRulesFromLegacyFormat(const QByteArray &data)
CachedSettingValue< bool > m_storeProcessingEnabled
void ruleChanged(const QString &ruleName)
void setDownloadRepacks(bool enabled)
bool isProcessingEnabled() const
bool hasRule(const QString &ruleName) const
QList< QSharedPointer< ProcessingJob > > m_processingQueue
QList< AutoDownloadRule > rules() const
QBasicTimer m_savingTimer
QByteArray exportRulesToLegacyFormat() const
void setRule_impl(const AutoDownloadRule &rule)
bool downloadRepacks() const
QHash< QString, AutoDownloadRule > m_rules
AsyncFileStorage * m_fileStorage
SettingValue< bool > m_storeDownloadRepacks
void setSmartEpisodeFilters(const QStringList &filters)
void removeRule(const QString &ruleName)
static QPointer< AutoDownloader > m_instance
void processingStateChanged(bool enabled)
SettingValue< QVariant > m_storeSmartEpisodeFilter
QTimer * m_processingTimer
void handleTorrentDownloadFinished(const QString &url)
bool renameRule(const QString &ruleName, const QString &newRuleName)
void resetProcessingQueue()
void processJob(const QSharedPointer< ProcessingJob > &job)
static AutoDownloader * instance()
void ruleAdded(const QString &ruleName)
~AutoDownloader() override
void timerEvent(QTimerEvent *event) override
void ruleAboutToBeRemoved(const QString &ruleName)
QHash< QString, QSharedPointer< ProcessingJob > > m_waitingJobs
void loadRules(const QByteArray &data)
void ruleRenamed(const QString &ruleName, const QString &oldRuleName)
AutoDownloadRule ruleByName(const QString &ruleName) const
QByteArray exportRules(RulesFileFormat format=RulesFileFormat::JSON) const
void handleNewArticle(const Article *article)
QRegularExpression smartEpisodeRegex() const
QStringList smartEpisodeFilters() const
void addJobForArticle(const Article *article)
void insertRule(const AutoDownloadRule &rule)
void setProcessingEnabled(bool enabled)
QRegularExpression m_smartEpisodeRegex
void handleTorrentDownloadFailed(const QString &url)
void importRules(const QByteArray &data, RulesFileFormat format=RulesFileFormat::JSON)
void importRulesFromJSONFormat(const QByteArray &data)
void newArticle(Article *article)
static Session * instance()
T get(const T &defaultValue={}) const
constexpr std::add_const_t< T > & asConst(T &t) noexcept
void LogMsg(const QString &message, const Log::MsgType &type)
QString fileName(const QString &filePath)
QString expandPathAbs(const QString &path)
SettingsStorage * settings()
QString specialFolderLocation(const SpecialFolder folder)
std::unique_ptr< QSettings > SettingsPtr
std::optional< bool > useAutoTMM
std::optional< bool > addPaused
std::optional< BitTorrent::TorrentContentLayout > contentLayout