mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-14 09:13:08 -07:00
More reliable folder scanning
This commit is contained in:
parent
ea1a54c5f1
commit
9c9944715a
3 changed files with 89 additions and 13 deletions
|
@ -19,6 +19,8 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
#ifndef CIFS_MAGIC_NUMBER
|
#ifndef CIFS_MAGIC_NUMBER
|
||||||
#define CIFS_MAGIC_NUMBER 0xFF534D42
|
#define CIFS_MAGIC_NUMBER 0xFF534D42
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,6 +29,9 @@
|
||||||
#define NFS_SUPER_MAGIC 0x6969
|
#define NFS_SUPER_MAGIC 0x6969
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const int WATCH_INTERVAL = 10000; // 10 sec
|
||||||
|
const int MAX_PARTIAL_RETRIES = 5;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subclassing QFileSystemWatcher in order to support Network File
|
* Subclassing QFileSystemWatcher in order to support Network File
|
||||||
* System watching (NFS, CIFS) on Linux and Mac OS.
|
* System watching (NFS, CIFS) on Linux and Mac OS.
|
||||||
|
@ -39,11 +44,14 @@ private:
|
||||||
QList<QDir> watched_folders;
|
QList<QDir> watched_folders;
|
||||||
QPointer<QTimer> watch_timer;
|
QPointer<QTimer> watch_timer;
|
||||||
#endif
|
#endif
|
||||||
QStringList filters;
|
QStringList m_filters;
|
||||||
|
// Partial torrents
|
||||||
|
QHash<QString, int> m_partialTorrents;
|
||||||
|
QPointer<QTimer> m_partialTorrentTimer;
|
||||||
|
|
||||||
#ifndef Q_WS_WIN
|
#ifndef Q_WS_WIN
|
||||||
protected:
|
private:
|
||||||
bool isNetworkFileSystem(QString path) {
|
static bool isNetworkFileSystem(QString path) {
|
||||||
QString file = path;
|
QString file = path;
|
||||||
if(!file.endsWith(QDir::separator()))
|
if(!file.endsWith(QDir::separator()))
|
||||||
file += QDir::separator();
|
file += QDir::separator();
|
||||||
|
@ -99,7 +107,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileSystemWatcher(QObject *parent): QFileSystemWatcher(parent) {
|
FileSystemWatcher(QObject *parent): QFileSystemWatcher(parent) {
|
||||||
filters << "*.torrent";
|
m_filters << "*.torrent";
|
||||||
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString)));
|
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +116,8 @@ public:
|
||||||
if(watch_timer)
|
if(watch_timer)
|
||||||
delete watch_timer;
|
delete watch_timer;
|
||||||
#endif
|
#endif
|
||||||
|
if(m_partialTorrentTimer)
|
||||||
|
delete m_partialTorrentTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList directories() const {
|
QStringList directories() const {
|
||||||
|
@ -137,7 +147,7 @@ public:
|
||||||
if (!watch_timer) {
|
if (!watch_timer) {
|
||||||
watch_timer = new QTimer(this);
|
watch_timer = new QTimer(this);
|
||||||
connect(watch_timer, SIGNAL(timeout()), this, SLOT(scanNetworkFolders()));
|
connect(watch_timer, SIGNAL(timeout()), this, SLOT(scanNetworkFolders()));
|
||||||
watch_timer->start(5000); // 5 sec
|
watch_timer->start(WATCH_INTERVAL); // 5 sec
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
|
@ -196,21 +206,74 @@ protected slots:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void processPartialTorrents() {
|
||||||
|
QStringList no_longer_partial;
|
||||||
|
|
||||||
|
// Check which torrents are still partial
|
||||||
|
foreach(const QString& torrent_path, m_partialTorrents.keys()) {
|
||||||
|
if(!QFile::exists(torrent_path)) {
|
||||||
|
m_partialTorrents.remove(torrent_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(misc::isValidTorrentFile(torrent_path)) {
|
||||||
|
no_longer_partial << torrent_path;
|
||||||
|
m_partialTorrents.remove(torrent_path);
|
||||||
|
} else {
|
||||||
|
if(m_partialTorrents[torrent_path] >= MAX_PARTIAL_RETRIES) {
|
||||||
|
m_partialTorrents.remove(torrent_path);
|
||||||
|
QFile::rename(torrent_path, torrent_path+".invalid");
|
||||||
|
} else {
|
||||||
|
m_partialTorrents[torrent_path]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the partial timer if necessary
|
||||||
|
if(m_partialTorrents.empty()) {
|
||||||
|
m_partialTorrentTimer->stop();
|
||||||
|
m_partialTorrentTimer->deleteLater();
|
||||||
|
qDebug("No longer any partial torrent.");
|
||||||
|
} else {
|
||||||
|
qDebug("Still %d partial torrents after delayed processing.", m_partialTorrents.count());
|
||||||
|
m_partialTorrentTimer->start(WATCH_INTERVAL);
|
||||||
|
}
|
||||||
|
// Notify of new torrents
|
||||||
|
if(!no_longer_partial.isEmpty())
|
||||||
|
emit torrentsAdded(no_longer_partial);
|
||||||
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void torrentsAdded(QStringList &pathList);
|
void torrentsAdded(QStringList &pathList);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addTorrentsFromDir(const QDir &dir, QStringList &torrents) {
|
void startPartialTorrentTimer() {
|
||||||
const QStringList files = dir.entryList(filters, QDir::Files, QDir::Unsorted);
|
Q_ASSERT(!m_partialTorrents.isEmpty());
|
||||||
foreach(const QString &file, files) {
|
if(!m_partialTorrentTimer) {
|
||||||
#if defined(Q_WS_WIN) || defined(Q_OS_OS2)
|
m_partialTorrentTimer = new QTimer();
|
||||||
torrents << dir.absoluteFilePath(file).replace("/", "\\");
|
connect(m_partialTorrentTimer, SIGNAL(timeout()), SLOT(processPartialTorrents()));
|
||||||
#else
|
m_partialTorrentTimer->setSingleShot(true);
|
||||||
torrents << dir.absoluteFilePath(file);
|
m_partialTorrentTimer->start(WATCH_INTERVAL);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addTorrentsFromDir(const QDir &dir, QStringList &torrents) {
|
||||||
|
const QStringList files = dir.entryList(m_filters, QDir::Files, QDir::Unsorted);
|
||||||
|
foreach(const QString &file, files) {
|
||||||
|
const QString file_abspath = dir.absoluteFilePath(file);
|
||||||
|
if(misc::isValidTorrentFile(file_abspath)) {
|
||||||
|
torrents << file_abspath;
|
||||||
|
} else {
|
||||||
|
if(!m_partialTorrents.contains(file_abspath)) {
|
||||||
|
qDebug("Partial torrent detected at: %s", qPrintable(file_abspath));
|
||||||
|
qDebug("Delay the file's processing...");
|
||||||
|
m_partialTorrents.insert(file_abspath, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!m_partialTorrents.empty())
|
||||||
|
startPartialTorrentTimer();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FILESYSTEMWATCHER_H
|
#endif // FILESYSTEMWATCHER_H
|
||||||
|
|
11
src/misc.cpp
11
src/misc.cpp
|
@ -748,3 +748,14 @@ quint64 misc::computePathSize(QString path)
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool misc::isValidTorrentFile(const QString &torrent_path) {
|
||||||
|
try {
|
||||||
|
boost::intrusive_ptr<libtorrent::torrent_info> t = new torrent_info(torrent_path.toUtf8().constData());
|
||||||
|
if(!t->is_valid() || t->num_files() == 0)
|
||||||
|
throw std::exception();
|
||||||
|
} catch(std::exception&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -170,6 +170,8 @@ public:
|
||||||
static QStringList toStringList(const QList<bool> &l);
|
static QStringList toStringList(const QList<bool> &l);
|
||||||
static QList<int> intListfromStringList(const QStringList &l);
|
static QList<int> intListfromStringList(const QStringList &l);
|
||||||
static QList<bool> boolListfromStringList(const QStringList &l);
|
static QList<bool> boolListfromStringList(const QStringList &l);
|
||||||
|
|
||||||
|
static bool isValidTorrentFile(const QString &path);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Trick to get a portable sleep() function
|
// Trick to get a portable sleep() function
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue