mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-02-01 01:16:01 +00:00
- FEATURE: Folder scanning now works with CIFS and NFS mounted folders
This commit is contained in:
parent
a6f31c7950
commit
daef9ece75
@ -16,6 +16,7 @@
|
|||||||
- FEATURE: Dropped Qt 4.3 support (Qt >= 4.4 is required)
|
- FEATURE: Dropped Qt 4.3 support (Qt >= 4.4 is required)
|
||||||
- FEATURE: Display more information regarding the torrent in its properties
|
- FEATURE: Display more information regarding the torrent in its properties
|
||||||
- FEATURE: Various optimizations to save CPU and memory
|
- FEATURE: Various optimizations to save CPU and memory
|
||||||
|
- FEATURE: Folder scanning now works with CIFS and NFS mounted folders
|
||||||
- COSMETIC: Merged download / upload lists
|
- COSMETIC: Merged download / upload lists
|
||||||
- COSMETIC: Torrents can be filtered based on their status
|
- COSMETIC: Torrents can be filtered based on their status
|
||||||
- COSMETIC: Torrent properties are now displayed in main window
|
- COSMETIC: Torrent properties are now displayed in main window
|
||||||
|
@ -32,10 +32,9 @@
|
|||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QFileSystemWatcher>
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QMutex>
|
|
||||||
|
|
||||||
|
#include "filesystemwatcher.h"
|
||||||
#include "bittorrent.h"
|
#include "bittorrent.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "downloadThread.h"
|
#include "downloadThread.h"
|
||||||
@ -89,9 +88,6 @@ bittorrent::bittorrent() : DHTEnabled(false), preAllocateAll(false), addInPause(
|
|||||||
downloader = new downloadThread(this);
|
downloader = new downloadThread(this);
|
||||||
connect(downloader, SIGNAL(downloadFinished(QString, QString)), this, SLOT(processDownloadedFile(QString, QString)));
|
connect(downloader, SIGNAL(downloadFinished(QString, QString)), this, SLOT(processDownloadedFile(QString, QString)));
|
||||||
connect(downloader, SIGNAL(downloadFailure(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
|
connect(downloader, SIGNAL(downloadFailure(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
|
||||||
BigRatioTimer = 0;
|
|
||||||
filterParser = 0;
|
|
||||||
FSWatcher = 0;
|
|
||||||
qDebug("* BTSession constructed");
|
qDebug("* BTSession constructed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +110,6 @@ bittorrent::~bittorrent() {
|
|||||||
delete downloader;
|
delete downloader;
|
||||||
if(FSWatcher) {
|
if(FSWatcher) {
|
||||||
delete FSWatcher;
|
delete FSWatcher;
|
||||||
delete FSMutex;
|
|
||||||
}
|
}
|
||||||
// Delete BT session
|
// Delete BT session
|
||||||
qDebug("Deleting session");
|
qDebug("Deleting session");
|
||||||
@ -969,25 +964,10 @@ bool bittorrent::isFilePreviewPossible(QString hash) const{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan the first level of the directory for torrent files
|
void bittorrent::addTorrentsFromScanFolder(QStringList &pathList) {
|
||||||
// and add them to download list
|
QString dir_path = FSWatcher->directories().first();
|
||||||
void bittorrent::scanDirectory(QString scan_dir) {
|
foreach(const QString &file, pathList) {
|
||||||
FSMutex->lock();
|
QString fullPath = dir_path+QDir::separator()+file;
|
||||||
qDebug("Scanning directory: %s", scan_dir.toLocal8Bit().data());
|
|
||||||
QDir dir(scan_dir);
|
|
||||||
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup");
|
|
||||||
// Check that scan dir is not BT_backup (silly but who knows...)
|
|
||||||
if(dir == torrentBackup) {
|
|
||||||
std::cerr << "Scan directory cannot be qBittorrent backup folder!" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QStringList filters;
|
|
||||||
filters << "*.torrent";
|
|
||||||
QStringList files = dir.entryList(filters, QDir::Files, QDir::Unsorted);
|
|
||||||
foreach(const QString &file, files) {
|
|
||||||
QString fullPath = dir.path()+QDir::separator()+file;
|
|
||||||
QFile torrent(fullPath);
|
|
||||||
qDebug("Adding for scan_dir: %s", fullPath.toLocal8Bit().data());
|
|
||||||
try {
|
try {
|
||||||
torrent_info t(fullPath.toLocal8Bit().data());
|
torrent_info t(fullPath.toLocal8Bit().data());
|
||||||
addTorrent(fullPath, true);
|
addTorrent(fullPath, true);
|
||||||
@ -995,7 +975,6 @@ void bittorrent::scanDirectory(QString scan_dir) {
|
|||||||
qDebug("Ignoring incomplete torrent file: %s", fullPath.toLocal8Bit().data());
|
qDebug("Ignoring incomplete torrent file: %s", fullPath.toLocal8Bit().data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FSMutex->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bittorrent::setDefaultSavePath(QString savepath) {
|
void bittorrent::setDefaultSavePath(QString savepath) {
|
||||||
@ -1050,21 +1029,17 @@ void bittorrent::enableDirectoryScanning(QString scan_dir) {
|
|||||||
newDir.mkpath(scan_dir);
|
newDir.mkpath(scan_dir);
|
||||||
}
|
}
|
||||||
if(FSWatcher == 0) {
|
if(FSWatcher == 0) {
|
||||||
FSMutex = new QMutex();
|
// Set up folder watching
|
||||||
FSWatcher = new QFileSystemWatcher(QStringList(scan_dir), this);
|
FSWatcher = new FileSystemWatcher(scan_dir, this);
|
||||||
connect(FSWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(scanDirectory(QString)));
|
connect(FSWatcher, SIGNAL(torrentsAdded(QStringList&)), this, SLOT(addTorrentsFromScanFolder(QStringList&)));
|
||||||
// Initial scan
|
|
||||||
scanDirectory(scan_dir);
|
|
||||||
} else {
|
} else {
|
||||||
QString old_scan_dir = "";
|
QString old_scan_dir = "";
|
||||||
if(!FSWatcher->directories().empty())
|
if(!FSWatcher->directories().empty())
|
||||||
old_scan_dir = FSWatcher->directories().first();
|
old_scan_dir = FSWatcher->directories().first();
|
||||||
if(old_scan_dir != scan_dir) {
|
if(QDir(old_scan_dir) != QDir(scan_dir)) {
|
||||||
if(!old_scan_dir.isEmpty())
|
if(!old_scan_dir.isEmpty())
|
||||||
FSWatcher->removePath(old_scan_dir);
|
FSWatcher->removePath(old_scan_dir);
|
||||||
FSWatcher->addPath(scan_dir);
|
FSWatcher->addPath(scan_dir);
|
||||||
// Initial scan
|
|
||||||
scanDirectory(scan_dir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1074,7 +1049,6 @@ void bittorrent::enableDirectoryScanning(QString scan_dir) {
|
|||||||
void bittorrent::disableDirectoryScanning() {
|
void bittorrent::disableDirectoryScanning() {
|
||||||
if(FSWatcher) {
|
if(FSWatcher) {
|
||||||
delete FSWatcher;
|
delete FSWatcher;
|
||||||
delete FSMutex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,8 +44,7 @@ using namespace libtorrent;
|
|||||||
|
|
||||||
class downloadThread;
|
class downloadThread;
|
||||||
class QTimer;
|
class QTimer;
|
||||||
class QFileSystemWatcher;
|
class FileSystemWatcher;
|
||||||
class QMutex;
|
|
||||||
class FilterParserThread;
|
class FilterParserThread;
|
||||||
|
|
||||||
class bittorrent : public QObject {
|
class bittorrent : public QObject {
|
||||||
@ -53,8 +52,7 @@ class bittorrent : public QObject {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
session *s;
|
session *s;
|
||||||
QPointer<QFileSystemWatcher> FSWatcher;
|
QPointer<FileSystemWatcher> FSWatcher;
|
||||||
QMutex* FSMutex;
|
|
||||||
QPointer<QTimer> timerAlerts;
|
QPointer<QTimer> timerAlerts;
|
||||||
QPointer<QTimer> BigRatioTimer;
|
QPointer<QTimer> BigRatioTimer;
|
||||||
bool DHTEnabled;
|
bool DHTEnabled;
|
||||||
@ -172,7 +170,7 @@ class bittorrent : public QObject {
|
|||||||
void downloadFromURLList(const QStringList& urls);
|
void downloadFromURLList(const QStringList& urls);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void scanDirectory(QString);
|
void addTorrentsFromScanFolder(QStringList&);
|
||||||
void readAlerts();
|
void readAlerts();
|
||||||
void loadTrackerFile(QString hash);
|
void loadTrackerFile(QString hash);
|
||||||
void deleteBigRatios();
|
void deleteBigRatios();
|
||||||
|
182
src/filesystemwatcher.h
Normal file
182
src/filesystemwatcher.h
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#ifndef FILESYSTEMWATCHER_H
|
||||||
|
#define FILESYSTEMWATCHER_H
|
||||||
|
|
||||||
|
#include <QFileSystemWatcher>
|
||||||
|
|
||||||
|
#ifndef Q_WS_WIN
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QSet>
|
||||||
|
#include <iostream>
|
||||||
|
#include <errno.h>
|
||||||
|
#ifdef Q_WS_MAC
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#else
|
||||||
|
#include <sys/vfs.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CIFS_MAGIC_NUMBER
|
||||||
|
#define CIFS_MAGIC_NUMBER 0xFF534D42
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NFS_SUPER_MAGIC
|
||||||
|
#define NFS_SUPER_MAGIC 0x6969
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Subclassing QFileSystemWatcher in order to support Network File
|
||||||
|
* System watching (NFS, CIFS) on Linux and Mac OS.
|
||||||
|
*/
|
||||||
|
class FileSystemWatcher: public QFileSystemWatcher {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
#ifndef Q_WS_WIN
|
||||||
|
private:
|
||||||
|
QDir watched_folder;
|
||||||
|
QPointer<QTimer> watch_timer;
|
||||||
|
QStringList filters;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool isNetworkFileSystem(QString path) {
|
||||||
|
QString file = path;
|
||||||
|
if(!file.endsWith(QDir::separator()))
|
||||||
|
file += QDir::separator();
|
||||||
|
file += ".";
|
||||||
|
struct statfs buf;
|
||||||
|
if(!statfs(file.toLocal8Bit().data(), &buf)) {
|
||||||
|
return (buf.f_type == (long)CIFS_MAGIC_NUMBER || buf.f_type == (long)NFS_SUPER_MAGIC);
|
||||||
|
} else {
|
||||||
|
std::cerr << "Error: statfs() call failed for " << file.toLocal8Bit().data() << ". Supposing it is a local folder..." << std::endl;
|
||||||
|
switch(errno) {
|
||||||
|
case EACCES:
|
||||||
|
std::cerr << "Search permission is denied for a component of the path prefix of the path" << std::endl;
|
||||||
|
break;
|
||||||
|
case EFAULT:
|
||||||
|
std::cerr << "Buf or path points to an invalid address" << std::endl;
|
||||||
|
break;
|
||||||
|
case EINTR:
|
||||||
|
std::cerr << "This call was interrupted by a signal" << std::endl;
|
||||||
|
break;
|
||||||
|
case EIO:
|
||||||
|
std::cerr << "I/O Error" << std::endl;
|
||||||
|
break;
|
||||||
|
case ELOOP:
|
||||||
|
std::cerr << "Too many symlinks" << std::endl;
|
||||||
|
break;
|
||||||
|
case ENAMETOOLONG:
|
||||||
|
std::cerr << "path is too long" << std::endl;
|
||||||
|
break;
|
||||||
|
case ENOENT:
|
||||||
|
std::cerr << "The file referred by path does not exist" << std::endl;
|
||||||
|
break;
|
||||||
|
case ENOMEM:
|
||||||
|
std::cerr << "Insufficient kernel memory" << std::endl;
|
||||||
|
break;
|
||||||
|
case ENOSYS:
|
||||||
|
std::cerr << "The file system does not detect this call" << std::endl;
|
||||||
|
break;
|
||||||
|
case ENOTDIR:
|
||||||
|
std::cerr << "A component of the path is not a directory" << std::endl;
|
||||||
|
break;
|
||||||
|
case EOVERFLOW:
|
||||||
|
std::cerr << "Some values were too large to be represented in the struct" << std::endl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cerr << "Unknown error" << std::endl;
|
||||||
|
}
|
||||||
|
std::cerr << "Errno: " << errno << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileSystemWatcher(QObject *parent): QFileSystemWatcher(parent) {
|
||||||
|
filters << "*.torrent";
|
||||||
|
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanFolder()));
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystemWatcher(QString path, QObject *parent): QFileSystemWatcher(parent) {
|
||||||
|
filters << "*.torrent";
|
||||||
|
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanFolder()));
|
||||||
|
addPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
~FileSystemWatcher() {
|
||||||
|
#ifndef Q_WS_WIN
|
||||||
|
if(watch_timer)
|
||||||
|
delete watch_timer;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList directories() const {
|
||||||
|
#ifndef Q_WS_WIN
|
||||||
|
if(watch_timer)
|
||||||
|
return QStringList(watched_folder.path());
|
||||||
|
#endif
|
||||||
|
return QFileSystemWatcher::directories();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addPath(const QString & path) {
|
||||||
|
#ifndef Q_WS_WIN
|
||||||
|
watched_folder = QDir(path);
|
||||||
|
if(!watched_folder.exists()) return;
|
||||||
|
// Check if the path points to a network file system or not
|
||||||
|
if(isNetworkFileSystem(path)) {
|
||||||
|
// Network mode
|
||||||
|
Q_ASSERT(!watch_timer);
|
||||||
|
qDebug("Network folder detected: %s", path.toLocal8Bit().data());
|
||||||
|
qDebug("Using file polling mode instead of inotify...");
|
||||||
|
// Set up the watch timer
|
||||||
|
watch_timer = new QTimer(this);
|
||||||
|
connect(watch_timer, SIGNAL(timeout()), this, SLOT(scanFolder()));
|
||||||
|
watch_timer->start(5000); // 5 sec
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
// Normal mode
|
||||||
|
QFileSystemWatcher::addPath(path);
|
||||||
|
scanFolder();
|
||||||
|
#ifndef Q_WS_WIN
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void removePath(const QString & path) {
|
||||||
|
#ifndef Q_WS_WIN
|
||||||
|
if(watch_timer) {
|
||||||
|
// Network mode
|
||||||
|
if(QDir(path) == watched_folder) {
|
||||||
|
delete watch_timer;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
// Normal mode
|
||||||
|
QFileSystemWatcher::removePath(path);
|
||||||
|
#ifndef Q_WS_WIN
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
// XXX: Does not detect file size changes to improve performance.
|
||||||
|
void scanFolder() {
|
||||||
|
QStringList torrents;
|
||||||
|
if(watch_timer)
|
||||||
|
torrents = watched_folder.entryList(filters, QDir::Files, QDir::Unsorted);
|
||||||
|
else
|
||||||
|
torrents = QDir(QFileSystemWatcher::directories().first()).entryList(filters, QDir::Files, QDir::Unsorted);
|
||||||
|
if(!torrents.empty())
|
||||||
|
emit torrentsAdded(torrents);
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void torrentsAdded(QStringList &pathList);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILESYSTEMWATCHER_H
|
@ -184,7 +184,8 @@ HEADERS += GUI.h \
|
|||||||
TransferListDelegate.h \
|
TransferListDelegate.h \
|
||||||
TransferListFiltersWidget.h \
|
TransferListFiltersWidget.h \
|
||||||
propertieswidget.h \
|
propertieswidget.h \
|
||||||
TorrentFilesModel.h
|
TorrentFilesModel.h \
|
||||||
|
filesystemwatcher.h
|
||||||
FORMS += MainWindow.ui \
|
FORMS += MainWindow.ui \
|
||||||
options.ui \
|
options.ui \
|
||||||
about.ui \
|
about.ui \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user