qBittorrent
TorrentFilesWatcher::Worker Class Referencefinal
Inheritance diagram for TorrentFilesWatcher::Worker:
Collaboration diagram for TorrentFilesWatcher::Worker:

Public Slots

void setWatchedFolder (const QString &path, const TorrentFilesWatcher::WatchedFolderOptions &options)
 
void removeWatchedFolder (const QString &path)
 

Signals

void magnetFound (const BitTorrent::MagnetUri &magnetURI, const BitTorrent::AddTorrentParams &addTorrentParams)
 
void torrentFound (const BitTorrent::TorrentInfo &torrentInfo, const BitTorrent::AddTorrentParams &addTorrentParams)
 

Public Member Functions

 Worker ()
 

Private Member Functions

void onTimeout ()
 
void scheduleWatchedFolderProcessing (const QString &path)
 
void processWatchedFolder (const QString &path)
 
void processFolder (const QString &path, const QString &watchedFolderPath, const TorrentFilesWatcher::WatchedFolderOptions &options)
 
void processFailedTorrents ()
 
void addWatchedFolder (const QString &watchedFolderID, const TorrentFilesWatcher::WatchedFolderOptions &options)
 
void updateWatchedFolder (const QString &watchedFolderID, const TorrentFilesWatcher::WatchedFolderOptions &options)
 

Private Attributes

QFileSystemWatcher * m_watcher = nullptr
 
QTimer * m_watchTimer = nullptr
 
QHash< QString, TorrentFilesWatcher::WatchedFolderOptionsm_watchedFolders
 
QSet< QString > m_watchedByTimeoutFolders
 
QTimer * m_retryTorrentTimer = nullptr
 
QHash< QString, QHash< QString, int > > m_failedTorrents
 

Detailed Description

Definition at line 202 of file torrentfileswatcher.cpp.

Constructor & Destructor Documentation

◆ Worker()

TorrentFilesWatcher::Worker::Worker ( )

Definition at line 445 of file torrentfileswatcher.cpp.

446  : m_watcher {new QFileSystemWatcher(this)}
447  , m_watchTimer {new QTimer(this)}
448  , m_retryTorrentTimer {new QTimer(this)}
449 {
450  connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &Worker::scheduleWatchedFolderProcessing);
451  connect(m_watchTimer, &QTimer::timeout, this, &Worker::onTimeout);
452 
453  connect(m_retryTorrentTimer, &QTimer::timeout, this, &Worker::processFailedTorrents);
454 }
void scheduleWatchedFolderProcessing(const QString &path)

References m_retryTorrentTimer, m_watcher, m_watchTimer, onTimeout(), processFailedTorrents(), and scheduleWatchedFolderProcessing().

Here is the call graph for this function:

Member Function Documentation

◆ addWatchedFolder()

void TorrentFilesWatcher::Worker::addWatchedFolder ( const QString &  watchedFolderID,
const TorrentFilesWatcher::WatchedFolderOptions options 
)
private

Definition at line 634 of file torrentfileswatcher.cpp.

635 {
636 #if !defined Q_OS_HAIKU
637  // Check if the path points to a network file system or not
638  if (Utils::Fs::isNetworkFileSystem(path) || options.recursive)
639 #else
640  if (options.recursive)
641 #endif
642  {
643  m_watchedByTimeoutFolders.insert(path);
644  if (!m_watchTimer->isActive())
646  }
647  else
648  {
649  m_watcher->addPath(path);
651  }
652 
653  m_watchedFolders[path] = options;
654 
655  LogMsg(tr("Watching folder: \"%1\"").arg(Utils::Fs::toNativePath(path)));
656 }
QHash< QString, TorrentFilesWatcher::WatchedFolderOptions > m_watchedFolders
void LogMsg(const QString &message, const Log::MsgType &type)
Definition: logger.cpp:125
bool isNetworkFileSystem(const QString &path)
Definition: fs.cpp:337
QString toNativePath(const QString &path)
Definition: fs.cpp:64
const std::chrono::duration WATCH_INTERVAL

References Utils::Fs::isNetworkFileSystem(), LogMsg(), TorrentFilesWatcher::m_watchedFolders, TorrentFilesWatcher::WatchedFolderOptions::recursive, Utils::Fs::toNativePath(), and WATCH_INTERVAL.

Here is the call graph for this function:

◆ magnetFound

void TorrentFilesWatcher::Worker::magnetFound ( const BitTorrent::MagnetUri magnetURI,
const BitTorrent::AddTorrentParams addTorrentParams 
)
signal

Referenced by TorrentFilesWatcher::TorrentFilesWatcher().

Here is the caller graph for this function:

◆ onTimeout()

void TorrentFilesWatcher::Worker::onTimeout ( )
private

Definition at line 456 of file torrentfileswatcher.cpp.

457 {
458  for (const QString &path : asConst(m_watchedByTimeoutFolders))
459  processWatchedFolder(path);
460 }
void processWatchedFolder(const QString &path)
constexpr std::add_const_t< T > & asConst(T &t) noexcept
Definition: global.h:42

References asConst().

Referenced by Worker().

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

◆ processFailedTorrents()

void TorrentFilesWatcher::Worker::processFailedTorrents ( )
private

Definition at line 573 of file torrentfileswatcher.cpp.

574 {
575  // Check which torrents are still partial
576  Algorithm::removeIf(m_failedTorrents, [this](const QString &watchedFolderPath, QHash<QString, int> &partialTorrents)
577  {
578  const QDir dir {watchedFolderPath};
579  const TorrentFilesWatcher::WatchedFolderOptions options = m_watchedFolders.value(watchedFolderPath);
580  Algorithm::removeIf(partialTorrents, [this, &dir, &options](const QString &torrentPath, int &value)
581  {
582  if (!QFile::exists(torrentPath))
583  return true;
584 
585  const nonstd::expected<BitTorrent::TorrentInfo, QString> result = BitTorrent::TorrentInfo::loadFromFile(torrentPath);
586  if (result)
587  {
588  BitTorrent::AddTorrentParams addTorrentParams = options.addTorrentParams;
589  const QString exactDirPath = QFileInfo(torrentPath).canonicalPath();
590  if (exactDirPath != dir.path())
591  {
592  const QString subdirPath = dir.relativeFilePath(exactDirPath);
593  if (addTorrentParams.useAutoTMM)
594  {
595  addTorrentParams.category = addTorrentParams.category.isEmpty()
596  ? subdirPath : (addTorrentParams.category + QLatin1Char('/') + subdirPath);
597  }
598  else
599  {
600  addTorrentParams.savePath = QDir(addTorrentParams.savePath).filePath(subdirPath);
601  }
602  }
603 
604  emit torrentFound(result.value(), addTorrentParams);
605  Utils::Fs::forceRemove(torrentPath);
606 
607  return true;
608  }
609 
610  if (value >= MAX_FAILED_RETRIES)
611  {
612  LogMsg(tr("Rejecting failed torrent file: %1").arg(torrentPath));
613  QFile::rename(torrentPath, torrentPath + ".qbt_rejected");
614  return true;
615  }
616 
617  ++value;
618  return false;
619  });
620 
621  if (partialTorrents.isEmpty())
622  return true;
623 
624  return false;
625  });
626 
627  // Stop the partial timer if necessary
628  if (m_failedTorrents.empty())
629  m_retryTorrentTimer->stop();
630  else
632 }
static nonstd::expected< TorrentInfo, QString > loadFromFile(const QString &path) noexcept
void torrentFound(const BitTorrent::TorrentInfo &torrentInfo, const BitTorrent::AddTorrentParams &addTorrentParams)
QHash< QString, QHash< QString, int > > m_failedTorrents
void removeIf(T &dict, BinaryPredicate &&p)
Definition: algorithm.h:50
bool forceRemove(const QString &filePath)
Definition: fs.cpp:173
T value(const QString &key, const T &defaultValue={})
Definition: preferences.cpp:64
std::optional< bool > useAutoTMM
BitTorrent::AddTorrentParams addTorrentParams
const int MAX_FAILED_RETRIES

References TorrentFilesWatcher::WatchedFolderOptions::addTorrentParams, BitTorrent::AddTorrentParams::category, Utils::Fs::forceRemove(), BitTorrent::TorrentInfo::loadFromFile(), LogMsg(), TorrentFilesWatcher::m_watchedFolders, MAX_FAILED_RETRIES, Algorithm::removeIf(), BitTorrent::AddTorrentParams::savePath, BitTorrent::AddTorrentParams::useAutoTMM, anonymous_namespace{preferences.cpp}::value(), and WATCH_INTERVAL.

Referenced by Worker().

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

◆ processFolder()

void TorrentFilesWatcher::Worker::processFolder ( const QString &  path,
const QString &  watchedFolderPath,
const TorrentFilesWatcher::WatchedFolderOptions options 
)
private

Definition at line 501 of file torrentfileswatcher.cpp.

503 {
504  const QDir watchedDir {watchedFolderPath};
505 
506  QDirIterator dirIter {path, {"*.torrent", "*.magnet"}, QDir::Files};
507  while (dirIter.hasNext())
508  {
509  const QString filePath = dirIter.next();
510  BitTorrent::AddTorrentParams addTorrentParams = options.addTorrentParams;
511  if (path != watchedFolderPath)
512  {
513  const QString subdirPath = watchedDir.relativeFilePath(path);
514  if (addTorrentParams.useAutoTMM)
515  {
516  addTorrentParams.category = addTorrentParams.category.isEmpty()
517  ? subdirPath : (addTorrentParams.category + QLatin1Char('/') + subdirPath);
518  }
519  else
520  {
521  addTorrentParams.savePath = QDir::cleanPath(QDir(addTorrentParams.savePath).filePath(subdirPath));
522  }
523  }
524 
525  if (filePath.endsWith(QLatin1String(".magnet"), Qt::CaseInsensitive))
526  {
527  QFile file {filePath};
528  if (file.open(QIODevice::ReadOnly | QIODevice::Text))
529  {
530  QTextStream str {&file};
531  while (!str.atEnd())
532  emit magnetFound(BitTorrent::MagnetUri(str.readLine()), addTorrentParams);
533 
534  file.close();
535  Utils::Fs::forceRemove(filePath);
536  }
537  else
538  {
539  LogMsg(tr("Failed to open magnet file: %1").arg(file.errorString()));
540  }
541  }
542  else
543  {
544  const nonstd::expected<BitTorrent::TorrentInfo, QString> result = BitTorrent::TorrentInfo::loadFromFile(filePath);
545  if (result)
546  {
547  emit torrentFound(result.value(), addTorrentParams);
548  Utils::Fs::forceRemove(filePath);
549  }
550  else
551  {
552  if (!m_failedTorrents.value(path).contains(filePath))
553  {
554  m_failedTorrents[path][filePath] = 0;
555  }
556  }
557  }
558  }
559 
560  if (options.recursive)
561  {
562  QDirIterator dirIter {path, (QDir::Dirs | QDir::NoDot | QDir::NoDotDot)};
563  while (dirIter.hasNext())
564  {
565  const QString folderPath = dirIter.next();
566  // Skip processing of subdirectory that is explicitly set as watched folder
567  if (!m_watchedFolders.contains(folderPath))
568  processFolder(folderPath, watchedFolderPath, options);
569  }
570  }
571 }
void processFolder(const QString &path, const QString &watchedFolderPath, const TorrentFilesWatcher::WatchedFolderOptions &options)
void magnetFound(const BitTorrent::MagnetUri &magnetURI, const BitTorrent::AddTorrentParams &addTorrentParams)
file(GLOB QBT_TS_FILES "${qBittorrent_SOURCE_DIR}/src/lang/*.ts") set_source_files_properties($
Definition: CMakeLists.txt:5

References TorrentFilesWatcher::WatchedFolderOptions::addTorrentParams, BitTorrent::AddTorrentParams::category, file(), Utils::Fs::forceRemove(), BitTorrent::TorrentInfo::loadFromFile(), LogMsg(), TorrentFilesWatcher::m_watchedFolders, TorrentFilesWatcher::WatchedFolderOptions::recursive, BitTorrent::AddTorrentParams::savePath, and BitTorrent::AddTorrentParams::useAutoTMM.

Here is the call graph for this function:

◆ processWatchedFolder()

void TorrentFilesWatcher::Worker::processWatchedFolder ( const QString &  path)
private

Definition at line 492 of file torrentfileswatcher.cpp.

493 {
495  processFolder(path, path, options);
496 
497  if (!m_failedTorrents.empty() && !m_retryTorrentTimer->isActive())
499 }

References TorrentFilesWatcher::m_watchedFolders, and WATCH_INTERVAL.

◆ removeWatchedFolder

void TorrentFilesWatcher::Worker::removeWatchedFolder ( const QString &  path)
slot

Definition at line 470 of file torrentfileswatcher.cpp.

471 {
472  m_watchedFolders.remove(path);
473 
474  m_watcher->removePath(path);
475  m_watchedByTimeoutFolders.remove(path);
476  if (m_watchedByTimeoutFolders.isEmpty())
477  m_watchTimer->stop();
478 
479  m_failedTorrents.remove(path);
480  if (m_failedTorrents.isEmpty())
481  m_retryTorrentTimer->stop();
482 }

References TorrentFilesWatcher::m_watchedFolders.

Referenced by TorrentFilesWatcher::removeWatchedFolder().

Here is the caller graph for this function:

◆ scheduleWatchedFolderProcessing()

void TorrentFilesWatcher::Worker::scheduleWatchedFolderProcessing ( const QString &  path)
private

Definition at line 484 of file torrentfileswatcher.cpp.

485 {
486  QTimer::singleShot(2000, this, [this, path]()
487  {
488  processWatchedFolder(path);
489  });
490 }

Referenced by Worker().

Here is the caller graph for this function:

◆ setWatchedFolder

void TorrentFilesWatcher::Worker::setWatchedFolder ( const QString &  path,
const TorrentFilesWatcher::WatchedFolderOptions options 
)
slot

Definition at line 462 of file torrentfileswatcher.cpp.

463 {
464  if (m_watchedFolders.contains(path))
465  updateWatchedFolder(path, options);
466  else
467  addWatchedFolder(path, options);
468 }
void updateWatchedFolder(const QString &watchedFolderID, const TorrentFilesWatcher::WatchedFolderOptions &options)
void addWatchedFolder(const QString &watchedFolderID, const TorrentFilesWatcher::WatchedFolderOptions &options)

References TorrentFilesWatcher::m_watchedFolders.

Referenced by TorrentFilesWatcher::doSetWatchedFolder().

Here is the caller graph for this function:

◆ torrentFound

void TorrentFilesWatcher::Worker::torrentFound ( const BitTorrent::TorrentInfo torrentInfo,
const BitTorrent::AddTorrentParams addTorrentParams 
)
signal

Referenced by TorrentFilesWatcher::TorrentFilesWatcher().

Here is the caller graph for this function:

◆ updateWatchedFolder()

void TorrentFilesWatcher::Worker::updateWatchedFolder ( const QString &  watchedFolderID,
const TorrentFilesWatcher::WatchedFolderOptions options 
)
private

Definition at line 658 of file torrentfileswatcher.cpp.

659 {
660  const bool recursiveModeChanged = (m_watchedFolders[path].recursive != options.recursive);
661 #if !defined Q_OS_HAIKU
662  if (recursiveModeChanged && !Utils::Fs::isNetworkFileSystem(path))
663 #else
664  if (recursiveModeChanged)
665 #endif
666  {
667  if (options.recursive)
668  {
669  m_watcher->removePath(path);
670 
671  m_watchedByTimeoutFolders.insert(path);
672  if (!m_watchTimer->isActive())
674  }
675  else
676  {
677  m_watchedByTimeoutFolders.remove(path);
678  if (m_watchedByTimeoutFolders.isEmpty())
679  m_watchTimer->stop();
680 
681  m_watcher->addPath(path);
683  }
684  }
685 
686  m_watchedFolders[path] = options;
687 }

References Utils::Fs::isNetworkFileSystem(), TorrentFilesWatcher::m_watchedFolders, TorrentFilesWatcher::WatchedFolderOptions::recursive, and WATCH_INTERVAL.

Here is the call graph for this function:

Member Data Documentation

◆ m_failedTorrents

QHash<QString, QHash<QString, int> > TorrentFilesWatcher::Worker::m_failedTorrents
private

Definition at line 234 of file torrentfileswatcher.cpp.

◆ m_retryTorrentTimer

QTimer* TorrentFilesWatcher::Worker::m_retryTorrentTimer = nullptr
private

Definition at line 233 of file torrentfileswatcher.cpp.

Referenced by Worker().

◆ m_watchedByTimeoutFolders

QSet<QString> TorrentFilesWatcher::Worker::m_watchedByTimeoutFolders
private

Definition at line 230 of file torrentfileswatcher.cpp.

◆ m_watchedFolders

QHash<QString, TorrentFilesWatcher::WatchedFolderOptions> TorrentFilesWatcher::Worker::m_watchedFolders
private

Definition at line 229 of file torrentfileswatcher.cpp.

◆ m_watcher

QFileSystemWatcher* TorrentFilesWatcher::Worker::m_watcher = nullptr
private

Definition at line 227 of file torrentfileswatcher.cpp.

Referenced by Worker().

◆ m_watchTimer

QTimer* TorrentFilesWatcher::Worker::m_watchTimer = nullptr
private

Definition at line 228 of file torrentfileswatcher.cpp.

Referenced by Worker().


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