qBittorrent
RSS::AutoDownloadRule Class Reference

#include <rss_autodownloadrule.h>

Public Member Functions

 AutoDownloadRule (const QString &name="")
 
 AutoDownloadRule (const AutoDownloadRule &other)
 
 ~AutoDownloadRule ()
 
QString name () const
 
void setName (const QString &name)
 
bool isEnabled () const
 
void setEnabled (bool enable)
 
QString mustContain () const
 
void setMustContain (const QString &tokens)
 
QString mustNotContain () const
 
void setMustNotContain (const QString &tokens)
 
QStringList feedURLs () const
 
void setFeedURLs (const QStringList &urls)
 
int ignoreDays () const
 
void setIgnoreDays (int d)
 
QDateTime lastMatch () const
 
void setLastMatch (const QDateTime &lastMatch)
 
bool useRegex () const
 
void setUseRegex (bool enabled)
 
bool useSmartFilter () const
 
void setUseSmartFilter (bool enabled)
 
QString episodeFilter () const
 
void setEpisodeFilter (const QString &e)
 
QStringList previouslyMatchedEpisodes () const
 
void setPreviouslyMatchedEpisodes (const QStringList &previouslyMatchedEpisodes)
 
QString savePath () const
 
void setSavePath (const QString &savePath)
 
std::optional< bool > addPaused () const
 
void setAddPaused (std::optional< bool > addPaused)
 
std::optional< BitTorrent::TorrentContentLayouttorrentContentLayout () const
 
void setTorrentContentLayout (std::optional< BitTorrent::TorrentContentLayout > contentLayout)
 
QString assignedCategory () const
 
void setCategory (const QString &category)
 
bool matches (const QVariantHash &articleData) const
 
bool accepts (const QVariantHash &articleData)
 
AutoDownloadRuleoperator= (const AutoDownloadRule &other)
 
bool operator== (const AutoDownloadRule &other) const
 
bool operator!= (const AutoDownloadRule &other) const
 
QJsonObject toJsonObject () const
 
QVariantHash toLegacyDict () const
 

Static Public Member Functions

static AutoDownloadRule fromJsonObject (const QJsonObject &jsonObj, const QString &name="")
 
static AutoDownloadRule fromLegacyDict (const QVariantHash &dict)
 

Private Member Functions

bool matchesMustContainExpression (const QString &articleTitle) const
 
bool matchesMustNotContainExpression (const QString &articleTitle) const
 
bool matchesEpisodeFilterExpression (const QString &articleTitle) const
 
bool matchesSmartEpisodeFilter (const QString &articleTitle) const
 
bool matchesExpression (const QString &articleTitle, const QString &expression) const
 
QRegularExpression cachedRegex (const QString &expression, bool isRegex=true) const
 

Private Attributes

QSharedDataPointer< AutoDownloadRuleDatam_dataPtr
 

Detailed Description

Definition at line 47 of file rss_autodownloadrule.h.

Constructor & Destructor Documentation

◆ AutoDownloadRule() [1/2]

AutoDownloadRule::AutoDownloadRule ( const QString &  name = "")
explicit

Definition at line 193 of file rss_autodownloadrule.cpp.

195 {
196  setName(name);
197 }
QSharedDataPointer< AutoDownloadRuleData > m_dataPtr
void setName(const QString &name)

References name(), and setName().

Here is the call graph for this function:

◆ AutoDownloadRule() [2/2]

AutoDownloadRule::AutoDownloadRule ( const AutoDownloadRule other)

Definition at line 199 of file rss_autodownloadrule.cpp.

200  : m_dataPtr(other.m_dataPtr)
201 {
202 }

◆ ~AutoDownloadRule()

AutoDownloadRule::~AutoDownloadRule ( )

Definition at line 204 of file rss_autodownloadrule.cpp.

204 {}

Member Function Documentation

◆ accepts()

bool AutoDownloadRule::accepts ( const QVariantHash &  articleData)

Definition at line 424 of file rss_autodownloadrule.cpp.

425 {
426  if (!matches(articleData))
427  return false;
428 
429  setLastMatch(articleData[Article::KeyDate].toDateTime());
430 
431  // If there's a matched episode string, add that to the previously matched list
432  if (!m_dataPtr->lastComputedEpisodes.isEmpty())
433  {
434  m_dataPtr->previouslyMatchedEpisodes.append(m_dataPtr->lastComputedEpisodes);
435  m_dataPtr->lastComputedEpisodes.clear();
436  }
437 
438  return true;
439 }
static const QString KeyDate
Definition: rss_article.h:54
void setLastMatch(const QDateTime &lastMatch)
bool matches(const QVariantHash &articleData) const

References RSS::Article::KeyDate, m_dataPtr, matches(), and setLastMatch().

Here is the call graph for this function:

◆ addPaused()

std::optional< bool > AutoDownloadRule::addPaused ( ) const

Definition at line 637 of file rss_autodownloadrule.cpp.

638 {
639  return m_dataPtr->addPaused;
640 }

References m_dataPtr.

Referenced by setAddPaused(), toJsonObject(), toLegacyDict(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

◆ assignedCategory()

QString AutoDownloadRule::assignedCategory ( ) const

Definition at line 657 of file rss_autodownloadrule.cpp.

658 {
659  return m_dataPtr->category;
660 }

References m_dataPtr.

Referenced by toJsonObject(), toLegacyDict(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

◆ cachedRegex()

QRegularExpression AutoDownloadRule::cachedRegex ( const QString &  expression,
bool  isRegex = true 
) const
private

Definition at line 206 of file rss_autodownloadrule.cpp.

207 {
208  // Use a cache of regexes so we don't have to continually recompile - big performance increase.
209  // The cache is cleared whenever the regex/wildcard, must or must not contain fields or
210  // episode filter are modified.
211  Q_ASSERT(!expression.isEmpty());
212 
213  QRegularExpression &regex = m_dataPtr->cachedRegexes[expression];
214  if (regex.pattern().isEmpty())
215  {
216  const QString pattern = (isRegex ? expression : Utils::String::wildcardToRegexPattern(expression));
217  regex = QRegularExpression {pattern, QRegularExpression::CaseInsensitiveOption};
218  }
219 
220  return regex;
221 }
QString wildcardToRegexPattern(const QString &pattern)
Definition: string.cpp:57

References m_dataPtr, and Utils::String::wildcardToRegexPattern().

Referenced by matchesEpisodeFilterExpression(), and matchesExpression().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ episodeFilter()

QString AutoDownloadRule::episodeFilter ( ) const

Definition at line 738 of file rss_autodownloadrule.cpp.

739 {
740  return m_dataPtr->episodeFilter;
741 }

References m_dataPtr.

Referenced by toJsonObject(), toLegacyDict(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

◆ feedURLs()

QStringList AutoDownloadRule::feedURLs ( ) const

Definition at line 607 of file rss_autodownloadrule.cpp.

608 {
609  return m_dataPtr->feedURLs;
610 }

References m_dataPtr.

Referenced by fromJsonObject(), AutomatedRssDownloader::handleFeedCheckStateChange(), RSSController::matchingArticlesAction(), toJsonObject(), toLegacyDict(), and AutomatedRssDownloader::updateMatchingArticles().

Here is the caller graph for this function:

◆ fromJsonObject()

AutoDownloadRule AutoDownloadRule::fromJsonObject ( const QJsonObject &  jsonObj,
const QString &  name = "" 
)
static

Definition at line 479 of file rss_autodownloadrule.cpp.

480 {
481  AutoDownloadRule rule(name.isEmpty() ? jsonObj.value(Str_Name).toString() : name);
482 
483  rule.setUseRegex(jsonObj.value(Str_UseRegex).toBool(false));
484  rule.setMustContain(jsonObj.value(Str_MustContain).toString());
485  rule.setMustNotContain(jsonObj.value(Str_MustNotContain).toString());
486  rule.setEpisodeFilter(jsonObj.value(Str_EpisodeFilter).toString());
487  rule.setEnabled(jsonObj.value(Str_Enabled).toBool(true));
488  rule.setSavePath(jsonObj.value(Str_SavePath).toString());
489  rule.setCategory(jsonObj.value(Str_AssignedCategory).toString());
490  rule.setAddPaused(toOptionalBool(jsonObj.value(Str_AddPaused)));
491 
492  // TODO: The following code is deprecated. Replace with the commented one after several releases in 4.4.x.
493  // === BEGIN DEPRECATED CODE === //
494  if (jsonObj.contains(Str_ContentLayout))
495  {
496  rule.setTorrentContentLayout(jsonValueToContentLayout(jsonObj.value(Str_ContentLayout)));
497  }
498  else
499  {
500  const std::optional<bool> createSubfolder = toOptionalBool(jsonObj.value(Str_CreateSubfolder));
501  std::optional<BitTorrent::TorrentContentLayout> contentLayout;
502  if (createSubfolder.has_value())
503  {
504  contentLayout = (*createSubfolder
505  ? BitTorrent::TorrentContentLayout::Original
506  : BitTorrent::TorrentContentLayout::NoSubfolder);
507  }
508 
509  rule.setTorrentContentLayout(contentLayout);
510  }
511  // === END DEPRECATED CODE === //
512  // === BEGIN REPLACEMENT CODE === //
513 // rule.setTorrentContentLayout(jsonValueToContentLayout(jsonObj.value(Str_ContentLayout)));
514  // === END REPLACEMENT CODE === //
515 
516  rule.setLastMatch(QDateTime::fromString(jsonObj.value(Str_LastMatch).toString(), Qt::RFC2822Date));
517  rule.setIgnoreDays(jsonObj.value(Str_IgnoreDays).toInt());
518  rule.setUseSmartFilter(jsonObj.value(Str_SmartFilter).toBool(false));
519 
520  const QJsonValue feedsVal = jsonObj.value(Str_AffectedFeeds);
521  QStringList feedURLs;
522  if (feedsVal.isString())
523  feedURLs << feedsVal.toString();
524  else for (const QJsonValue &urlVal : asConst(feedsVal.toArray()))
525  feedURLs << urlVal.toString();
526  rule.setFeedURLs(feedURLs);
527 
528  const QJsonValue previouslyMatchedVal = jsonObj.value(Str_PreviouslyMatched);
529  QStringList previouslyMatched;
530  if (previouslyMatchedVal.isString())
531  {
532  previouslyMatched << previouslyMatchedVal.toString();
533  }
534  else
535  {
536  for (const QJsonValue &val : asConst(previouslyMatchedVal.toArray()))
537  previouslyMatched << val.toString();
538  }
539  rule.setPreviouslyMatchedEpisodes(previouslyMatched);
540 
541  return rule;
542 }
QStringList feedURLs() const
constexpr std::add_const_t< T > & asConst(T &t) noexcept
Definition: global.h:42
std::optional< bool > toOptionalBool(const QJsonValue &jsonVal)
std::optional< BitTorrent::TorrentContentLayout > jsonValueToContentLayout(const QJsonValue &jsonVal)
const QString Str_SavePath(QStringLiteral("savePath"))
const QString Str_UseRegex(QStringLiteral("useRegex"))
const QString Str_AffectedFeeds(QStringLiteral("affectedFeeds"))
const QString Str_EpisodeFilter(QStringLiteral("episodeFilter"))
const QString Str_CreateSubfolder(QStringLiteral("createSubfolder"))
const QString Str_MustNotContain(QStringLiteral("mustNotContain"))
const QString Str_PreviouslyMatched(QStringLiteral("previouslyMatchedEpisodes"))
const QString Str_IgnoreDays(QStringLiteral("ignoreDays"))
const QString Str_ContentLayout(QStringLiteral("torrentContentLayout"))
const QString Str_MustContain(QStringLiteral("mustContain"))
const QString Str_SmartFilter(QStringLiteral("smartFilter"))
const QString Str_AssignedCategory(QStringLiteral("assignedCategory"))
const QString Str_AddPaused(QStringLiteral("addPaused"))
const QString Str_LastMatch(QStringLiteral("lastMatch"))
const QString Str_Name(QStringLiteral("name"))
const QString Str_Enabled(QStringLiteral("enabled"))

References asConst(), feedURLs(), anonymous_namespace{rss_autodownloadrule.cpp}::jsonValueToContentLayout(), name(), setAddPaused(), setCategory(), setEnabled(), setEpisodeFilter(), setFeedURLs(), setIgnoreDays(), setLastMatch(), setMustContain(), setMustNotContain(), setPreviouslyMatchedEpisodes(), setSavePath(), setTorrentContentLayout(), setUseRegex(), setUseSmartFilter(), Str_AddPaused(), Str_AffectedFeeds(), Str_AssignedCategory(), Str_ContentLayout(), Str_CreateSubfolder(), Str_Enabled(), Str_EpisodeFilter(), Str_IgnoreDays(), Str_LastMatch(), Str_MustContain(), Str_MustNotContain(), Str_Name(), Str_PreviouslyMatched(), Str_SavePath(), Str_SmartFilter(), Str_UseRegex(), and anonymous_namespace{rss_autodownloadrule.cpp}::toOptionalBool().

Referenced by anonymous_namespace{rss_autodownloader.cpp}::rulesFromJSON(), and RSSController::setRuleAction().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fromLegacyDict()

AutoDownloadRule AutoDownloadRule::fromLegacyDict ( const QVariantHash &  dict)
static

Definition at line 560 of file rss_autodownloadrule.cpp.

561 {
562  AutoDownloadRule rule(dict.value("name").toString());
563 
564  rule.setUseRegex(dict.value("use_regex", false).toBool());
565  rule.setMustContain(dict.value("must_contain").toString());
566  rule.setMustNotContain(dict.value("must_not_contain").toString());
567  rule.setEpisodeFilter(dict.value("episode_filter").toString());
568  rule.setFeedURLs(dict.value("affected_feeds").toStringList());
569  rule.setEnabled(dict.value("enabled", false).toBool());
570  rule.setSavePath(dict.value("save_path").toString());
571  rule.setCategory(dict.value("category_assigned").toString());
572  rule.setAddPaused(addPausedLegacyToOptionalBool(dict.value("add_paused").toInt()));
573  rule.setLastMatch(dict.value("last_match").toDateTime());
574  rule.setIgnoreDays(dict.value("ignore_days").toInt());
575 
576  return rule;
577 }
std::optional< bool > addPausedLegacyToOptionalBool(const int val)

References anonymous_namespace{rss_autodownloadrule.cpp}::addPausedLegacyToOptionalBool(), setAddPaused(), setCategory(), setEnabled(), setEpisodeFilter(), setFeedURLs(), setIgnoreDays(), setLastMatch(), setMustContain(), setMustNotContain(), setSavePath(), and setUseRegex().

Referenced by RSS::AutoDownloader::importRulesFromLegacyFormat(), and RSS::AutoDownloader::loadRulesLegacy().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ignoreDays()

int AutoDownloadRule::ignoreDays ( ) const

Definition at line 692 of file rss_autodownloadrule.cpp.

693 {
694  return m_dataPtr->ignoreDays;
695 }

References m_dataPtr.

Referenced by matches(), toJsonObject(), toLegacyDict(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

◆ isEnabled()

bool AutoDownloadRule::isEnabled ( ) const

Definition at line 667 of file rss_autodownloadrule.cpp.

668 {
669  return m_dataPtr->enabled;
670 }

References m_dataPtr.

Referenced by AutomatedRssDownloader::createRuleItem(), toJsonObject(), and toLegacyDict().

Here is the caller graph for this function:

◆ lastMatch()

QDateTime AutoDownloadRule::lastMatch ( ) const

Definition at line 677 of file rss_autodownloadrule.cpp.

678 {
679  return m_dataPtr->lastMatch;
680 }

References m_dataPtr.

Referenced by matches(), setLastMatch(), toJsonObject(), toLegacyDict(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

◆ matches()

bool AutoDownloadRule::matches ( const QVariantHash &  articleData) const

Definition at line 402 of file rss_autodownloadrule.cpp.

403 {
404  const QDateTime articleDate {articleData[Article::KeyDate].toDateTime()};
405  if (ignoreDays() > 0)
406  {
407  if (lastMatch().isValid() && (articleDate < lastMatch().addDays(ignoreDays())))
408  return false;
409  }
410 
411  const QString articleTitle {articleData[Article::KeyTitle].toString()};
412  if (!matchesMustContainExpression(articleTitle))
413  return false;
414  if (!matchesMustNotContainExpression(articleTitle))
415  return false;
416  if (!matchesEpisodeFilterExpression(articleTitle))
417  return false;
418  if (!matchesSmartEpisodeFilter(articleTitle))
419  return false;
420 
421  return true;
422 }
static const QString KeyTitle
Definition: rss_article.h:55
bool matchesEpisodeFilterExpression(const QString &articleTitle) const
bool matchesSmartEpisodeFilter(const QString &articleTitle) const
bool matchesMustNotContainExpression(const QString &articleTitle) const
bool matchesMustContainExpression(const QString &articleTitle) const

References ignoreDays(), RSS::Article::KeyDate, RSS::Article::KeyTitle, lastMatch(), matchesEpisodeFilterExpression(), matchesMustContainExpression(), matchesMustNotContainExpression(), and matchesSmartEpisodeFilter().

Referenced by accepts(), RSSController::matchingArticlesAction(), and AutomatedRssDownloader::updateMatchingArticles().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ matchesEpisodeFilterExpression()

bool AutoDownloadRule::matchesEpisodeFilterExpression ( const QString &  articleTitle) const
private

Definition at line 280 of file rss_autodownloadrule.cpp.

281 {
282  // Reset the lastComputedEpisode, we don't want to leak it between matches
283  m_dataPtr->lastComputedEpisodes.clear();
284 
285  if (m_dataPtr->episodeFilter.isEmpty())
286  return true;
287 
288  const QRegularExpression filterRegex {cachedRegex("(^\\d{1,4})x(.*;$)")};
289  const QRegularExpressionMatch matcher {filterRegex.match(m_dataPtr->episodeFilter)};
290  if (!matcher.hasMatch())
291  return false;
292 
293  const QString season {matcher.captured(1)};
294  const QStringList episodes {matcher.captured(2).split(';')};
295  const int seasonOurs {season.toInt()};
296 
297  for (QString episode : episodes)
298  {
299  if (episode.isEmpty())
300  continue;
301 
302  // We need to trim leading zeroes, but if it's all zeros then we want episode zero.
303  while ((episode.size() > 1) && episode.startsWith('0'))
304  episode = episode.right(episode.size() - 1);
305 
306  if (episode.indexOf('-') != -1)
307  { // Range detected
308  const QString partialPattern1 {"\\bs0?(\\d{1,4})[ -_\\.]?e(0?\\d{1,4})(?:\\D|\\b)"};
309  const QString partialPattern2 {"\\b(\\d{1,4})x(0?\\d{1,4})(?:\\D|\\b)"};
310 
311  // Extract partial match from article and compare as digits
312  QRegularExpressionMatch matcher = cachedRegex(partialPattern1).match(articleTitle);
313  bool matched = matcher.hasMatch();
314 
315  if (!matched)
316  {
317  matcher = cachedRegex(partialPattern2).match(articleTitle);
318  matched = matcher.hasMatch();
319  }
320 
321  if (matched)
322  {
323  const int seasonTheirs {matcher.captured(1).toInt()};
324  const int episodeTheirs {matcher.captured(2).toInt()};
325 
326  if (episode.endsWith('-'))
327  { // Infinite range
328  const int episodeOurs {QStringView(episode).left(episode.size() - 1).toInt()};
329  if (((seasonTheirs == seasonOurs) && (episodeTheirs >= episodeOurs)) || (seasonTheirs > seasonOurs))
330  return true;
331  }
332  else
333  { // Normal range
334  const QStringList range {episode.split('-')};
335  Q_ASSERT(range.size() == 2);
336  if (range.first().toInt() > range.last().toInt())
337  continue; // Ignore this subrule completely
338 
339  const int episodeOursFirst {range.first().toInt()};
340  const int episodeOursLast {range.last().toInt()};
341  if ((seasonTheirs == seasonOurs) && ((episodeOursFirst <= episodeTheirs) && (episodeOursLast >= episodeTheirs)))
342  return true;
343  }
344  }
345  }
346  else
347  { // Single number
348  const QString expStr {QString::fromLatin1("\\b(?:s0?%1[ -_\\.]?e0?%2|%1x0?%2)(?:\\D|\\b)").arg(season, episode)};
349  if (cachedRegex(expStr).match(articleTitle).hasMatch())
350  return true;
351  }
352  }
353 
354  return false;
355 }
QRegularExpression cachedRegex(const QString &expression, bool isRegex=true) const

References cachedRegex(), and m_dataPtr.

Referenced by matches().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ matchesExpression()

bool AutoDownloadRule::matchesExpression ( const QString &  articleTitle,
const QString &  expression 
) const
private

Definition at line 223 of file rss_autodownloadrule.cpp.

224 {
225  const QRegularExpression whitespace {"\\s+"};
226 
227  if (expression.isEmpty())
228  {
229  // A regex of the form "expr|" will always match, so do the same for wildcards
230  return true;
231  }
232 
233  if (m_dataPtr->useRegex)
234  {
235  const QRegularExpression reg(cachedRegex(expression));
236  return reg.match(articleTitle).hasMatch();
237  }
238 
239  // Only match if every wildcard token (separated by spaces) is present in the article name.
240  // Order of wildcard tokens is unimportant (if order is important, they should have used *).
241  const QStringList wildcards {expression.split(whitespace, Qt::SkipEmptyParts)};
242  for (const QString &wildcard : wildcards)
243  {
244  const QRegularExpression reg {cachedRegex(wildcard, false)};
245  if (!reg.match(articleTitle).hasMatch())
246  return false;
247  }
248 
249  return true;
250 }

References cachedRegex(), and m_dataPtr.

Here is the call graph for this function:

◆ matchesMustContainExpression()

bool AutoDownloadRule::matchesMustContainExpression ( const QString &  articleTitle) const
private

Definition at line 252 of file rss_autodownloadrule.cpp.

253 {
254  if (m_dataPtr->mustContain.empty())
255  return true;
256 
257  // Each expression is either a regex, or a set of wildcards separated by whitespace.
258  // Accept if any complete expression matches.
259  return std::any_of(m_dataPtr->mustContain.cbegin(), m_dataPtr->mustContain.cend(), [this, &articleTitle](const QString &expression)
260  {
261  // A regex of the form "expr|" will always match, so do the same for wildcards
262  return matchesExpression(articleTitle, expression);
263  });
264 }

References m_dataPtr.

Referenced by matches().

Here is the caller graph for this function:

◆ matchesMustNotContainExpression()

bool AutoDownloadRule::matchesMustNotContainExpression ( const QString &  articleTitle) const
private

Definition at line 266 of file rss_autodownloadrule.cpp.

267 {
268  if (m_dataPtr->mustNotContain.empty())
269  return true;
270 
271  // Each expression is either a regex, or a set of wildcards separated by whitespace.
272  // Reject if any complete expression matches.
273  return std::none_of(m_dataPtr->mustNotContain.cbegin(), m_dataPtr->mustNotContain.cend(), [this, &articleTitle](const QString &expression)
274  {
275  // A regex of the form "expr|" will always match, so do the same for wildcards
276  return matchesExpression(articleTitle, expression);
277  });
278 }

References m_dataPtr.

Referenced by matches().

Here is the caller graph for this function:

◆ matchesSmartEpisodeFilter()

bool AutoDownloadRule::matchesSmartEpisodeFilter ( const QString &  articleTitle) const
private

Definition at line 357 of file rss_autodownloadrule.cpp.

358 {
359  if (!useSmartFilter())
360  return true;
361 
362  const QString episodeStr = computeEpisodeName(articleTitle);
363  if (episodeStr.isEmpty())
364  return true;
365 
366  // See if this episode has been downloaded before
367  const bool previouslyMatched = m_dataPtr->previouslyMatchedEpisodes.contains(episodeStr);
368  if (previouslyMatched)
369  {
370  if (!AutoDownloader::instance()->downloadRepacks())
371  return false;
372 
373  // Now see if we've downloaded this particular repack/proper combination
374  const bool isRepack = articleTitle.contains("REPACK", Qt::CaseInsensitive);
375  const bool isProper = articleTitle.contains("PROPER", Qt::CaseInsensitive);
376 
377  if (!isRepack && !isProper)
378  return false;
379 
380  const QString fullEpisodeStr = QString::fromLatin1("%1%2%3").arg(episodeStr,
381  isRepack ? "-REPACK" : "",
382  isProper ? "-PROPER" : "");
383  const bool previouslyMatchedFull = m_dataPtr->previouslyMatchedEpisodes.contains(fullEpisodeStr);
384  if (previouslyMatchedFull)
385  return false;
386 
387  m_dataPtr->lastComputedEpisodes.append(fullEpisodeStr);
388 
389  // If this is a REPACK and PROPER download, add the individual entries to the list
390  // so we don't download those
391  if (isRepack && isProper)
392  {
393  m_dataPtr->lastComputedEpisodes.append(episodeStr + QLatin1String("-REPACK"));
394  m_dataPtr->lastComputedEpisodes.append(episodeStr + QLatin1String("-PROPER"));
395  }
396  }
397 
398  m_dataPtr->lastComputedEpisodes.append(episodeStr);
399  return true;
400 }
static AutoDownloader * instance()
QString computeEpisodeName(const QString &article)

References computeEpisodeName(), RSS::AutoDownloader::instance(), m_dataPtr, and useSmartFilter().

Referenced by matches().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mustContain()

QString AutoDownloadRule::mustContain ( ) const

Definition at line 697 of file rss_autodownloadrule.cpp.

698 {
699  return m_dataPtr->mustContain.join('|');
700 }

References m_dataPtr.

Referenced by toJsonObject(), toLegacyDict(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

◆ mustNotContain()

QString AutoDownloadRule::mustNotContain ( ) const

Definition at line 702 of file rss_autodownloadrule.cpp.

703 {
704  return m_dataPtr->mustNotContain.join('|');
705 }

References m_dataPtr.

Referenced by toJsonObject(), toLegacyDict(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

◆ name()

QString AutoDownloadRule::name ( ) const

◆ operator!=()

bool AutoDownloadRule::operator!= ( const AutoDownloadRule other) const

Definition at line 456 of file rss_autodownloadrule.cpp.

457 {
458  return !operator==(other);
459 }
bool operator==(const AutoDownloadRule &other) const

References operator==().

Here is the call graph for this function:

◆ operator=()

AutoDownloadRule & AutoDownloadRule::operator= ( const AutoDownloadRule other)

Definition at line 441 of file rss_autodownloadrule.cpp.

442 {
443  if (this != &other)
444  {
445  m_dataPtr = other.m_dataPtr;
446  }
447  return *this;
448 }

References m_dataPtr.

◆ operator==()

bool AutoDownloadRule::operator== ( const AutoDownloadRule other) const

Definition at line 450 of file rss_autodownloadrule.cpp.

451 {
452  return (m_dataPtr == other.m_dataPtr) // optimization
453  || (*m_dataPtr == *other.m_dataPtr);
454 }

References m_dataPtr.

Referenced by operator!=().

Here is the caller graph for this function:

◆ previouslyMatchedEpisodes()

QStringList AutoDownloadRule::previouslyMatchedEpisodes ( ) const

Definition at line 728 of file rss_autodownloadrule.cpp.

729 {
730  return m_dataPtr->previouslyMatchedEpisodes;
731 }

References m_dataPtr.

Referenced by setPreviouslyMatchedEpisodes(), and toJsonObject().

Here is the caller graph for this function:

◆ savePath()

QString AutoDownloadRule::savePath ( ) const

Definition at line 627 of file rss_autodownloadrule.cpp.

628 {
629  return m_dataPtr->savePath;
630 }

References m_dataPtr.

Referenced by setSavePath(), toJsonObject(), toLegacyDict(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

◆ setAddPaused()

void AutoDownloadRule::setAddPaused ( std::optional< bool >  addPaused)

Definition at line 642 of file rss_autodownloadrule.cpp.

643 {
644  m_dataPtr->addPaused = addPaused;
645 }
std::optional< bool > addPaused() const

References addPaused(), and m_dataPtr.

Referenced by fromJsonObject(), fromLegacyDict(), and AutomatedRssDownloader::updateEditedRule().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setCategory()

void AutoDownloadRule::setCategory ( const QString &  category)

Definition at line 662 of file rss_autodownloadrule.cpp.

663 {
664  m_dataPtr->category = category;
665 }

References m_dataPtr.

Referenced by fromJsonObject(), fromLegacyDict(), and AutomatedRssDownloader::updateEditedRule().

Here is the caller graph for this function:

◆ setEnabled()

void AutoDownloadRule::setEnabled ( bool  enable)

Definition at line 672 of file rss_autodownloadrule.cpp.

673 {
674  m_dataPtr->enabled = enable;
675 }

References m_dataPtr.

Referenced by fromJsonObject(), fromLegacyDict(), and AutomatedRssDownloader::updateEditedRule().

Here is the caller graph for this function:

◆ setEpisodeFilter()

void AutoDownloadRule::setEpisodeFilter ( const QString &  e)

Definition at line 743 of file rss_autodownloadrule.cpp.

744 {
745  m_dataPtr->episodeFilter = e;
746  m_dataPtr->cachedRegexes.clear();
747 }

References nova3.nova2dl::e, and m_dataPtr.

Referenced by fromJsonObject(), fromLegacyDict(), and AutomatedRssDownloader::updateEditedRule().

Here is the caller graph for this function:

◆ setFeedURLs()

void AutoDownloadRule::setFeedURLs ( const QStringList &  urls)

Definition at line 612 of file rss_autodownloadrule.cpp.

613 {
614  m_dataPtr->feedURLs = urls;
615 }

References m_dataPtr.

Referenced by fromJsonObject(), fromLegacyDict(), and AutomatedRssDownloader::handleFeedCheckStateChange().

Here is the caller graph for this function:

◆ setIgnoreDays()

void AutoDownloadRule::setIgnoreDays ( int  d)

Definition at line 687 of file rss_autodownloadrule.cpp.

688 {
689  m_dataPtr->ignoreDays = d;
690 }

References m_dataPtr.

Referenced by fromJsonObject(), fromLegacyDict(), and AutomatedRssDownloader::updateEditedRule().

Here is the caller graph for this function:

◆ setLastMatch()

void AutoDownloadRule::setLastMatch ( const QDateTime &  lastMatch)

Definition at line 682 of file rss_autodownloadrule.cpp.

683 {
684  m_dataPtr->lastMatch = lastMatch;
685 }

References lastMatch(), and m_dataPtr.

Referenced by accepts(), fromJsonObject(), and fromLegacyDict().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setMustContain()

void AutoDownloadRule::setMustContain ( const QString &  tokens)

Definition at line 579 of file rss_autodownloadrule.cpp.

580 {
581  m_dataPtr->cachedRegexes.clear();
582 
583  if (m_dataPtr->useRegex)
584  m_dataPtr->mustContain = QStringList() << tokens;
585  else
586  m_dataPtr->mustContain = tokens.split('|');
587 
588  // Check for single empty string - if so, no condition
589  if ((m_dataPtr->mustContain.size() == 1) && m_dataPtr->mustContain[0].isEmpty())
590  m_dataPtr->mustContain.clear();
591 }

References m_dataPtr.

Referenced by fromJsonObject(), fromLegacyDict(), and AutomatedRssDownloader::updateEditedRule().

Here is the caller graph for this function:

◆ setMustNotContain()

void AutoDownloadRule::setMustNotContain ( const QString &  tokens)

Definition at line 593 of file rss_autodownloadrule.cpp.

594 {
595  m_dataPtr->cachedRegexes.clear();
596 
597  if (m_dataPtr->useRegex)
598  m_dataPtr->mustNotContain = QStringList() << tokens;
599  else
600  m_dataPtr->mustNotContain = tokens.split('|');
601 
602  // Check for single empty string - if so, no condition
603  if ((m_dataPtr->mustNotContain.size() == 1) && m_dataPtr->mustNotContain[0].isEmpty())
604  m_dataPtr->mustNotContain.clear();
605 }

References m_dataPtr.

Referenced by fromJsonObject(), fromLegacyDict(), and AutomatedRssDownloader::updateEditedRule().

Here is the caller graph for this function:

◆ setName()

void AutoDownloadRule::setName ( const QString &  name)

Definition at line 622 of file rss_autodownloadrule.cpp.

623 {
624  m_dataPtr->name = name;
625 }

References m_dataPtr, and name().

Referenced by AutoDownloadRule(), AutomatedRssDownloader::handleRuleRenamed(), and RSS::AutoDownloader::renameRule().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setPreviouslyMatchedEpisodes()

void AutoDownloadRule::setPreviouslyMatchedEpisodes ( const QStringList &  previouslyMatchedEpisodes)

Definition at line 733 of file rss_autodownloadrule.cpp.

734 {
735  m_dataPtr->previouslyMatchedEpisodes = previouslyMatchedEpisodes;
736 }
QStringList previouslyMatchedEpisodes() const

References m_dataPtr, and previouslyMatchedEpisodes().

Referenced by AutomatedRssDownloader::clearSelectedRuleDownloadedEpisodeList(), and fromJsonObject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setSavePath()

void AutoDownloadRule::setSavePath ( const QString &  savePath)

Definition at line 632 of file rss_autodownloadrule.cpp.

633 {
635 }
QString toUniformPath(const QString &path)
Definition: fs.cpp:69

References m_dataPtr, savePath(), and Utils::Fs::toUniformPath().

Referenced by fromJsonObject(), fromLegacyDict(), and AutomatedRssDownloader::updateEditedRule().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setTorrentContentLayout()

void AutoDownloadRule::setTorrentContentLayout ( std::optional< BitTorrent::TorrentContentLayout contentLayout)

Definition at line 652 of file rss_autodownloadrule.cpp.

653 {
654  m_dataPtr->contentLayout = contentLayout;
655 }

References m_dataPtr.

Referenced by fromJsonObject(), and AutomatedRssDownloader::updateEditedRule().

Here is the caller graph for this function:

◆ setUseRegex()

void AutoDownloadRule::setUseRegex ( bool  enabled)

Definition at line 722 of file rss_autodownloadrule.cpp.

723 {
724  m_dataPtr->useRegex = enabled;
725  m_dataPtr->cachedRegexes.clear();
726 }

References m_dataPtr.

Referenced by fromJsonObject(), fromLegacyDict(), and AutomatedRssDownloader::updateEditedRule().

Here is the caller graph for this function:

◆ setUseSmartFilter()

void AutoDownloadRule::setUseSmartFilter ( bool  enabled)

Definition at line 712 of file rss_autodownloadrule.cpp.

713 {
714  m_dataPtr->smartFilter = enabled;
715 }

References m_dataPtr.

Referenced by fromJsonObject(), and AutomatedRssDownloader::updateEditedRule().

Here is the caller graph for this function:

◆ toJsonObject()

QJsonObject AutoDownloadRule::toJsonObject ( ) const

Definition at line 461 of file rss_autodownloadrule.cpp.

462 {
463  return {{Str_Enabled, isEnabled()}
464  , {Str_UseRegex, useRegex()}
468  , {Str_AffectedFeeds, QJsonArray::fromStringList(feedURLs())}
469  , {Str_SavePath, savePath()}
471  , {Str_LastMatch, lastMatch().toString(Qt::RFC2822Date)}
476  , {Str_PreviouslyMatched, QJsonArray::fromStringList(previouslyMatchedEpisodes())}};
477 }
std::optional< BitTorrent::TorrentContentLayout > torrentContentLayout() const
QJsonValue contentLayoutToJsonValue(const std::optional< BitTorrent::TorrentContentLayout > contentLayout)
QJsonValue toJsonValue(const std::optional< bool > boolValue)

References addPaused(), assignedCategory(), anonymous_namespace{rss_autodownloadrule.cpp}::contentLayoutToJsonValue(), episodeFilter(), feedURLs(), ignoreDays(), isEnabled(), lastMatch(), mustContain(), mustNotContain(), previouslyMatchedEpisodes(), savePath(), Str_AddPaused(), Str_AffectedFeeds(), Str_AssignedCategory(), Str_ContentLayout(), Str_Enabled(), Str_EpisodeFilter(), Str_IgnoreDays(), Str_LastMatch(), Str_MustContain(), Str_MustNotContain(), Str_PreviouslyMatched(), Str_SavePath(), Str_SmartFilter(), Str_UseRegex(), anonymous_namespace{rss_autodownloadrule.cpp}::toJsonValue(), torrentContentLayout(), useRegex(), and useSmartFilter().

Here is the call graph for this function:

◆ toLegacyDict()

QVariantHash AutoDownloadRule::toLegacyDict ( ) const

Definition at line 544 of file rss_autodownloadrule.cpp.

545 {
546  return {{"name", name()},
547  {"must_contain", mustContain()},
548  {"must_not_contain", mustNotContain()},
549  {"save_path", savePath()},
550  {"affected_feeds", feedURLs()},
551  {"enabled", isEnabled()},
552  {"category_assigned", assignedCategory()},
553  {"use_regex", useRegex()},
554  {"add_paused", toAddPausedLegacy(addPaused())},
555  {"episode_filter", episodeFilter()},
556  {"last_match", lastMatch()},
557  {"ignore_days", ignoreDays()}};
558 }
int toAddPausedLegacy(const std::optional< bool > boolValue)

References addPaused(), assignedCategory(), episodeFilter(), feedURLs(), ignoreDays(), isEnabled(), lastMatch(), mustContain(), mustNotContain(), name(), savePath(), anonymous_namespace{rss_autodownloadrule.cpp}::toAddPausedLegacy(), and useRegex().

Here is the call graph for this function:

◆ torrentContentLayout()

std::optional< BitTorrent::TorrentContentLayout > AutoDownloadRule::torrentContentLayout ( ) const

Definition at line 647 of file rss_autodownloadrule.cpp.

648 {
649  return m_dataPtr->contentLayout;
650 }

References m_dataPtr.

Referenced by toJsonObject(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

◆ useRegex()

bool AutoDownloadRule::useRegex ( ) const

Definition at line 717 of file rss_autodownloadrule.cpp.

718 {
719  return m_dataPtr->useRegex;
720 }

References m_dataPtr.

Referenced by toJsonObject(), toLegacyDict(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

◆ useSmartFilter()

bool AutoDownloadRule::useSmartFilter ( ) const

Definition at line 707 of file rss_autodownloadrule.cpp.

708 {
709  return m_dataPtr->smartFilter;
710 }

References m_dataPtr.

Referenced by matchesSmartEpisodeFilter(), toJsonObject(), and AutomatedRssDownloader::updateRuleDefinitionBox().

Here is the caller graph for this function:

Member Data Documentation

◆ m_dataPtr


The documentation for this class was generated from the following files: