|
|
|
@ -40,6 +40,7 @@
@@ -40,6 +40,7 @@
|
|
|
|
|
#include "misc.h" |
|
|
|
|
#include "downloadThread.h" |
|
|
|
|
#include "filterParserThread.h" |
|
|
|
|
#include "torrentPersistentData.h" |
|
|
|
|
#include <libtorrent/extensions/ut_metadata.hpp> |
|
|
|
|
#include <libtorrent/extensions/ut_pex.hpp> |
|
|
|
|
#include <libtorrent/extensions/smart_ban.hpp> |
|
|
|
@ -107,8 +108,8 @@ bittorrent::~bittorrent() {
@@ -107,8 +108,8 @@ bittorrent::~bittorrent() {
|
|
|
|
|
delete filterParser; |
|
|
|
|
delete downloader; |
|
|
|
|
if(FSWatcher) { |
|
|
|
|
delete FSWatcher; |
|
|
|
|
delete FSMutex; |
|
|
|
|
delete FSWatcher; |
|
|
|
|
delete FSMutex; |
|
|
|
|
} |
|
|
|
|
// Delete BT session
|
|
|
|
|
qDebug("Deleting session"); |
|
|
|
@ -126,22 +127,22 @@ void bittorrent::preAllocateAllFiles(bool b) {
@@ -126,22 +127,22 @@ void bittorrent::preAllocateAllFiles(bool b) {
|
|
|
|
|
|
|
|
|
|
void bittorrent::deleteBigRatios() { |
|
|
|
|
if(ratio_limit == -1) return; |
|
|
|
|
std::vector<torrent_handle> torrents = getTorrents(); |
|
|
|
|
std::vector<torrent_handle>::iterator torrentIT; |
|
|
|
|
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { |
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid()) continue; |
|
|
|
|
if(h.is_seed()) { |
|
|
|
|
QString hash = h.hash(); |
|
|
|
|
float ratio = getRealRatio(hash); |
|
|
|
|
if(ratio <= MAX_RATIO && ratio > ratio_limit) { |
|
|
|
|
QString fileName = h.name(); |
|
|
|
|
addConsoleMessage(tr("%1 reached the maximum ratio you set.").arg(fileName)); |
|
|
|
|
deleteTorrent(hash); |
|
|
|
|
//emit torrent_ratio_deleted(fileName);
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
std::vector<torrent_handle> torrents = getTorrents(); |
|
|
|
|
std::vector<torrent_handle>::iterator torrentIT; |
|
|
|
|
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { |
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid()) continue; |
|
|
|
|
if(h.is_seed()) { |
|
|
|
|
QString hash = h.hash(); |
|
|
|
|
float ratio = getRealRatio(hash); |
|
|
|
|
if(ratio <= MAX_RATIO && ratio > ratio_limit) { |
|
|
|
|
QString fileName = h.name(); |
|
|
|
|
addConsoleMessage(tr("%1 reached the maximum ratio you set.").arg(fileName)); |
|
|
|
|
deleteTorrent(hash); |
|
|
|
|
//emit torrent_ratio_deleted(fileName);
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::setDownloadLimit(QString hash, long val) { |
|
|
|
@ -206,22 +207,22 @@ int bittorrent::getUpTorrentPriority(QString hash) const {
@@ -206,22 +207,22 @@ int bittorrent::getUpTorrentPriority(QString hash) const {
|
|
|
|
|
// Calculate the ETA using GASA
|
|
|
|
|
// GASA: global Average Speed Algorithm
|
|
|
|
|
qlonglong bittorrent::getETA(QString hash) const { |
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
if(!h.is_valid()) return -1; |
|
|
|
|
switch(h.state()) { |
|
|
|
|
case torrent_status::downloading: { |
|
|
|
|
if(h.active_time() == 0) |
|
|
|
|
return -1; |
|
|
|
|
double avg_speed = (double)h.all_time_download() / h.active_time(); |
|
|
|
|
return (qlonglong) floor((double) (h.actual_size() - h.total_wanted_done()) / avg_speed); |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
if(!h.is_valid()) return -1; |
|
|
|
|
switch(h.state()) { |
|
|
|
|
case torrent_status::downloading: { |
|
|
|
|
if(h.active_time() == 0) |
|
|
|
|
return -1; |
|
|
|
|
double avg_speed = (double)h.all_time_download() / h.active_time(); |
|
|
|
|
return (qlonglong) floor((double) (h.actual_size() - h.total_wanted_done()) / avg_speed); |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::vector<torrent_handle> bittorrent::getTorrents() const { |
|
|
|
|
return s->get_torrents(); |
|
|
|
|
return s->get_torrents(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Return the torrent handle, given its hash
|
|
|
|
@ -232,28 +233,28 @@ QTorrentHandle bittorrent::getTorrentHandle(QString hash) const{
@@ -232,28 +233,28 @@ QTorrentHandle bittorrent::getTorrentHandle(QString hash) const{
|
|
|
|
|
unsigned int bittorrent::getFinishedPausedTorrentsNb() const { |
|
|
|
|
unsigned int nbPaused = 0; |
|
|
|
|
std::vector<torrent_handle> torrents = getTorrents(); |
|
|
|
|
std::vector<torrent_handle>::iterator torrentIT; |
|
|
|
|
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { |
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid()) continue; |
|
|
|
|
if(h.is_seed() && h.is_paused()) { |
|
|
|
|
++nbPaused; |
|
|
|
|
} |
|
|
|
|
std::vector<torrent_handle>::iterator torrentIT; |
|
|
|
|
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { |
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid()) continue; |
|
|
|
|
if(h.is_seed() && h.is_paused()) { |
|
|
|
|
++nbPaused; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return nbPaused; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned int bittorrent::getUnfinishedPausedTorrentsNb() const { |
|
|
|
|
unsigned int nbPaused = 0; |
|
|
|
|
std::vector<torrent_handle> torrents = getTorrents(); |
|
|
|
|
std::vector<torrent_handle>::iterator torrentIT; |
|
|
|
|
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { |
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid()) continue; |
|
|
|
|
if(!h.is_seed() && h.is_paused()) { |
|
|
|
|
++nbPaused; |
|
|
|
|
} |
|
|
|
|
std::vector<torrent_handle>::iterator torrentIT; |
|
|
|
|
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { |
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid()) continue; |
|
|
|
|
if(!h.is_seed() && h.is_paused()) { |
|
|
|
|
++nbPaused; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return nbPaused; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -270,7 +271,7 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) {
@@ -270,7 +271,7 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) {
|
|
|
|
|
QString fileName = h.name(); |
|
|
|
|
// Remove it from session
|
|
|
|
|
if(permanent) |
|
|
|
|
s->remove_torrent(h.get_torrent_handle(), session::delete_files); |
|
|
|
|
s->remove_torrent(h.get_torrent_handle(), session::delete_files); |
|
|
|
|
else |
|
|
|
|
s->remove_torrent(h.get_torrent_handle()); |
|
|
|
|
// Remove it from torrent backup directory
|
|
|
|
@ -281,6 +282,7 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) {
@@ -281,6 +282,7 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) {
|
|
|
|
|
foreach(const QString &file, files) { |
|
|
|
|
torrentBackup.remove(file); |
|
|
|
|
} |
|
|
|
|
TorrentPersistentData::deletePersistentData(hash); |
|
|
|
|
// Remove tracker errors
|
|
|
|
|
trackersErrors.remove(hash); |
|
|
|
|
if(permanent) |
|
|
|
@ -291,53 +293,49 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) {
@@ -291,53 +293,49 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::pauseAllTorrents() { |
|
|
|
|
std::vector<torrent_handle> torrents = getTorrents(); |
|
|
|
|
std::vector<torrent_handle>::iterator torrentIT; |
|
|
|
|
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { |
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid()) continue; |
|
|
|
|
if(!h.is_paused()) { |
|
|
|
|
h.pause(); |
|
|
|
|
emit pausedTorrent(h); |
|
|
|
|
} |
|
|
|
|
std::vector<torrent_handle> torrents = getTorrents(); |
|
|
|
|
std::vector<torrent_handle>::iterator torrentIT; |
|
|
|
|
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { |
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid()) continue; |
|
|
|
|
if(!h.is_paused()) { |
|
|
|
|
h.pause(); |
|
|
|
|
emit pausedTorrent(h); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::resumeAllTorrents() { |
|
|
|
|
std::vector<torrent_handle> torrents = getTorrents(); |
|
|
|
|
std::vector<torrent_handle>::iterator torrentIT; |
|
|
|
|
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { |
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid()) continue; |
|
|
|
|
if(h.is_paused()) { |
|
|
|
|
h.resume(); |
|
|
|
|
emit resumedTorrent(h); |
|
|
|
|
} |
|
|
|
|
std::vector<torrent_handle> torrents = getTorrents(); |
|
|
|
|
std::vector<torrent_handle>::iterator torrentIT; |
|
|
|
|
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) { |
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid()) continue; |
|
|
|
|
if(h.is_paused()) { |
|
|
|
|
h.resume(); |
|
|
|
|
emit resumedTorrent(h); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::pauseTorrent(QString hash) { |
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
if(!h.is_paused()) { |
|
|
|
|
h.pause(); |
|
|
|
|
emit pausedTorrent(h); |
|
|
|
|
} |
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
if(!h.is_paused()) { |
|
|
|
|
h.pause(); |
|
|
|
|
emit pausedTorrent(h); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::resumeTorrent(QString hash) { |
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
if(h.is_paused()) { |
|
|
|
|
h.resume(); |
|
|
|
|
emit resumedTorrent(h); |
|
|
|
|
} |
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
if(h.is_paused()) { |
|
|
|
|
h.resume(); |
|
|
|
|
emit resumedTorrent(h); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::loadWebSeeds(QString hash) { |
|
|
|
|
QFile urlseeds_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".urlseeds"); |
|
|
|
|
if(!urlseeds_file.open(QIODevice::ReadOnly | QIODevice::Text)) return; |
|
|
|
|
QByteArray urlseeds_lines = urlseeds_file.readAll(); |
|
|
|
|
urlseeds_file.close(); |
|
|
|
|
QList<QByteArray> url_seeds = urlseeds_lines.split('\n'); |
|
|
|
|
QVariantList url_seeds = TorrentPersistentData::getUrlSeeds(hash); |
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
// First remove from the torrent the url seeds that were deleted
|
|
|
|
|
// in a previous session
|
|
|
|
@ -352,7 +350,8 @@ void bittorrent::loadWebSeeds(QString hash) {
@@ -352,7 +350,8 @@ void bittorrent::loadWebSeeds(QString hash) {
|
|
|
|
|
h.remove_url_seed(existing_seed); |
|
|
|
|
} |
|
|
|
|
// Add the ones that were added in a previous session
|
|
|
|
|
foreach(const QByteArray &url_seed, url_seeds) { |
|
|
|
|
foreach(const QVariant &var_url_seed, url_seeds) { |
|
|
|
|
QString url_seed = var_url_seed.toString(); |
|
|
|
|
if(!url_seed.isEmpty()) { |
|
|
|
|
// XXX: Should we check if it is already in the list before adding it
|
|
|
|
|
// or is libtorrent clever enough to know
|
|
|
|
@ -362,11 +361,12 @@ void bittorrent::loadWebSeeds(QString hash) {
@@ -362,11 +361,12 @@ void bittorrent::loadWebSeeds(QString hash) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Add a torrent to the bittorrent session
|
|
|
|
|
QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString from_url, bool) { |
|
|
|
|
QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString from_url, bool resumed) { |
|
|
|
|
QTorrentHandle h; |
|
|
|
|
bool fastResume=false; |
|
|
|
|
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); |
|
|
|
|
QString file, dest_file; |
|
|
|
|
QString file, dest_file, hash; |
|
|
|
|
boost::intrusive_ptr<torrent_info> t; |
|
|
|
|
|
|
|
|
|
// Checking if BT_backup Dir exists
|
|
|
|
|
// create it if it is not
|
|
|
|
@ -382,75 +382,71 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr
@@ -382,75 +382,71 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr
|
|
|
|
|
return h; |
|
|
|
|
} |
|
|
|
|
Q_ASSERT(!file.startsWith("http://", Qt::CaseInsensitive) && !file.startsWith("https://", Qt::CaseInsensitive) && !file.startsWith("ftp://", Qt::CaseInsensitive)); |
|
|
|
|
|
|
|
|
|
qDebug("Adding %s to download list", file.toLocal8Bit().data()); |
|
|
|
|
boost::intrusive_ptr<torrent_info> t; |
|
|
|
|
try { |
|
|
|
|
// Getting torrent file informations
|
|
|
|
|
t = new torrent_info(file.toLocal8Bit().data()); |
|
|
|
|
// Getting torrent file informations
|
|
|
|
|
t = new torrent_info(file.toLocal8Bit().data()); |
|
|
|
|
} catch(std::exception&) { |
|
|
|
|
if(!from_url.isNull()) { |
|
|
|
|
addConsoleMessage(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(from_url), QString::fromUtf8("red")); |
|
|
|
|
//emit invalidTorrent(from_url);
|
|
|
|
|
QFile::remove(file); |
|
|
|
|
}else{ |
|
|
|
|
addConsoleMessage(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(file), QString::fromUtf8("red")); |
|
|
|
|
//emit invalidTorrent(file);
|
|
|
|
|
} |
|
|
|
|
addConsoleMessage(tr("This file is either corrupted or this isn't a torrent."),QString::fromUtf8("red")); |
|
|
|
|
if(fromScanDir) { |
|
|
|
|
// Remove file
|
|
|
|
|
QFile::remove(file); |
|
|
|
|
} |
|
|
|
|
return h; |
|
|
|
|
if(!from_url.isNull()) { |
|
|
|
|
addConsoleMessage(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(from_url), QString::fromUtf8("red")); |
|
|
|
|
//emit invalidTorrent(from_url);
|
|
|
|
|
QFile::remove(file); |
|
|
|
|
}else{ |
|
|
|
|
addConsoleMessage(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(file), QString::fromUtf8("red")); |
|
|
|
|
//emit invalidTorrent(file);
|
|
|
|
|
} |
|
|
|
|
addConsoleMessage(tr("This file is either corrupted or this isn't a torrent."),QString::fromUtf8("red")); |
|
|
|
|
if(fromScanDir) { |
|
|
|
|
// Remove file
|
|
|
|
|
QFile::remove(file); |
|
|
|
|
} |
|
|
|
|
return h; |
|
|
|
|
} |
|
|
|
|
qDebug(" -> Hash: %s", misc::toString(t->info_hash()).c_str()); |
|
|
|
|
qDebug(" -> Name: %s", t->name().c_str()); |
|
|
|
|
QString hash = misc::toQString(t->info_hash()); |
|
|
|
|
hash = misc::toQString(t->info_hash()); |
|
|
|
|
if(file.startsWith(torrentBackup.path())) { |
|
|
|
|
QFileInfo fi(file); |
|
|
|
|
QString old_hash = fi.baseName(); |
|
|
|
|
if(old_hash != hash){ |
|
|
|
|
qDebug("* ERROR: Strange, hash changed from %s to %s", old_hash.toLocal8Bit().data(), hash.toLocal8Bit().data()); |
|
|
|
|
} |
|
|
|
|
QFileInfo fi(file); |
|
|
|
|
QString old_hash = fi.baseName(); |
|
|
|
|
if(old_hash != hash){ |
|
|
|
|
qDebug("* ERROR: Strange, hash changed from %s to %s", old_hash.toLocal8Bit().data(), hash.toLocal8Bit().data()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Check if torrent is already in download list
|
|
|
|
|
if(s->find_torrent(t->info_hash()).is_valid()) { |
|
|
|
|
qDebug("/!\\ Torrent is already in download list"); |
|
|
|
|
// Update info Bar
|
|
|
|
|
if(!fromScanDir) { |
|
|
|
|
if(!from_url.isNull()) { |
|
|
|
|
// If download from url, remove temp file
|
|
|
|
|
QFile::remove(file); |
|
|
|
|
addConsoleMessage(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(from_url)); |
|
|
|
|
//emit duplicateTorrent(from_url);
|
|
|
|
|
}else{ |
|
|
|
|
addConsoleMessage(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(file)); |
|
|
|
|
//emit duplicateTorrent(file);
|
|
|
|
|
} |
|
|
|
|
qDebug("/!\\ Torrent is already in download list"); |
|
|
|
|
// Update info Bar
|
|
|
|
|
if(!fromScanDir) { |
|
|
|
|
if(!from_url.isNull()) { |
|
|
|
|
// If download from url, remove temp file
|
|
|
|
|
QFile::remove(file); |
|
|
|
|
addConsoleMessage(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(from_url)); |
|
|
|
|
//emit duplicateTorrent(from_url);
|
|
|
|
|
}else{ |
|
|
|
|
// Delete torrent from scan dir
|
|
|
|
|
QFile::remove(file); |
|
|
|
|
addConsoleMessage(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(file)); |
|
|
|
|
//emit duplicateTorrent(file);
|
|
|
|
|
} |
|
|
|
|
return h; |
|
|
|
|
}else{ |
|
|
|
|
// Delete torrent from scan dir
|
|
|
|
|
QFile::remove(file); |
|
|
|
|
} |
|
|
|
|
return h; |
|
|
|
|
} |
|
|
|
|
add_torrent_params p; |
|
|
|
|
//Getting fast resume data if existing
|
|
|
|
|
std::vector<char> buf; |
|
|
|
|
qDebug("Trying to load fastresume data: %s", (torrentBackup.path()+QDir::separator()+hash+QString(".fastresume")).toLocal8Bit().data()); |
|
|
|
|
if (load_file((torrentBackup.path()+QDir::separator()+hash+QString(".fastresume")).toLocal8Bit().data(), buf) == 0) { |
|
|
|
|
if(resumed) { |
|
|
|
|
qDebug("Trying to load fastresume data: %s", (torrentBackup.path()+QDir::separator()+hash+QString(".fastresume")).toLocal8Bit().data()); |
|
|
|
|
if (load_file((torrentBackup.path()+QDir::separator()+hash+QString(".fastresume")).toLocal8Bit().data(), buf) == 0) { |
|
|
|
|
fastResume = true; |
|
|
|
|
p.resume_data = &buf; |
|
|
|
|
qDebug("Successfuly loaded"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
QString savePath = getSavePath(hash); |
|
|
|
|
// Save save_path to hard drive
|
|
|
|
|
QFile savepath_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".savepath")); |
|
|
|
|
if(!savepath_file.exists()) { |
|
|
|
|
savepath_file.open(QIODevice::WriteOnly | QIODevice::Text); |
|
|
|
|
savepath_file.write(savePath.toLocal8Bit()); |
|
|
|
|
savepath_file.close(); |
|
|
|
|
} |
|
|
|
|
if(defaultTempPath.isEmpty() || QFile::exists(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".finished"))) { |
|
|
|
|
qDebug("addTorrent: using save_path: %s", savePath.toUtf8().data()); |
|
|
|
|
if(defaultTempPath.isEmpty() || (resumed && TorrentPersistentData::isSeed(hash))) { |
|
|
|
|
p.save_path = savePath.toLocal8Bit().data(); |
|
|
|
|
} else { |
|
|
|
|
p.save_path = defaultTempPath.toLocal8Bit().data(); |
|
|
|
@ -467,17 +463,17 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr
@@ -467,17 +463,17 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr
|
|
|
|
|
p.auto_managed = false; // Because it is added in paused state
|
|
|
|
|
// Adding torrent to bittorrent session
|
|
|
|
|
try { |
|
|
|
|
h = QTorrentHandle(s->add_torrent(p)); |
|
|
|
|
h = QTorrentHandle(s->add_torrent(p)); |
|
|
|
|
}catch(std::exception e){ |
|
|
|
|
qDebug("Error: %s", e.what()); |
|
|
|
|
} |
|
|
|
|
// Check if it worked
|
|
|
|
|
if(!h.is_valid()) { |
|
|
|
|
// No need to keep on, it failed.
|
|
|
|
|
qDebug("/!\\ Error: Invalid handle"); |
|
|
|
|
// If download from url, remove temp file
|
|
|
|
|
if(!from_url.isNull()) QFile::remove(file); |
|
|
|
|
return h; |
|
|
|
|
// No need to keep on, it failed.
|
|
|
|
|
qDebug("/!\\ Error: Invalid handle"); |
|
|
|
|
// If download from url, remove temp file
|
|
|
|
|
if(!from_url.isNull()) QFile::remove(file); |
|
|
|
|
return h; |
|
|
|
|
} |
|
|
|
|
// Connections limit per torrent
|
|
|
|
|
h.set_max_connections(maxConnecsPerTorrent); |
|
|
|
@ -485,76 +481,71 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr
@@ -485,76 +481,71 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr
|
|
|
|
|
h.set_max_uploads(maxUploadsPerTorrent); |
|
|
|
|
// Load filtered files
|
|
|
|
|
loadFilesPriorities(h); |
|
|
|
|
// Load custom url seeds
|
|
|
|
|
loadWebSeeds(hash); |
|
|
|
|
// Load speed limit from hard drive
|
|
|
|
|
loadTorrentSpeedLimits(hash); |
|
|
|
|
// Load trackers
|
|
|
|
|
bool loaded_trackers = loadTrackerFile(hash); |
|
|
|
|
// Doing this to order trackers well
|
|
|
|
|
if(!loaded_trackers) { |
|
|
|
|
saveTrackerFile(hash); |
|
|
|
|
loadTrackerFile(hash); |
|
|
|
|
if(resumed) { |
|
|
|
|
// Load custom url seeds
|
|
|
|
|
loadWebSeeds(hash); |
|
|
|
|
// Load speed limit from hard drive
|
|
|
|
|
loadTorrentSpeedLimits(hash); |
|
|
|
|
// Load trackers
|
|
|
|
|
loadTrackerFile(hash); |
|
|
|
|
} else { |
|
|
|
|
// Sequential download
|
|
|
|
|
if(TorrentTempData::hasTempData(hash)) { |
|
|
|
|
qDebug("addTorrent: Setting download as sequential (from tmp data)"); |
|
|
|
|
h.set_sequential_download(TorrentTempData::isSequential(hash)); |
|
|
|
|
} |
|
|
|
|
// Save persistent data for new torrent
|
|
|
|
|
TorrentPersistentData::saveTorrentPersistentData(h); |
|
|
|
|
// Save save_path
|
|
|
|
|
if(!defaultTempPath.isEmpty()) { |
|
|
|
|
qDebug("addTorrent: Saving save_path in persistent data: %s", savePath.toUtf8().data()); |
|
|
|
|
TorrentPersistentData::saveSavePath(hash, savePath); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
QString newFile = torrentBackup.path() + QDir::separator() + hash + ".torrent"; |
|
|
|
|
if(file != newFile) { |
|
|
|
|
// Delete file from torrentBackup directory in case it exists because
|
|
|
|
|
// QFile::copy() do not overwrite
|
|
|
|
|
QFile::remove(newFile); |
|
|
|
|
// Copy it to torrentBackup directory
|
|
|
|
|
QFile::copy(file, newFile); |
|
|
|
|
} |
|
|
|
|
// Incremental download
|
|
|
|
|
if(QFile::exists(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".incremental")) { |
|
|
|
|
qDebug("Incremental download enabled for %s", t->name().c_str()); |
|
|
|
|
h.set_sequential_download(true); |
|
|
|
|
// Delete file from torrentBackup directory in case it exists because
|
|
|
|
|
// QFile::copy() do not overwrite
|
|
|
|
|
QFile::remove(newFile); |
|
|
|
|
// Copy it to torrentBackup directory
|
|
|
|
|
QFile::copy(file, newFile); |
|
|
|
|
} |
|
|
|
|
if(!addInPause && !fastResume) { |
|
|
|
|
// Start torrent because it was added in paused state
|
|
|
|
|
h.resume(); |
|
|
|
|
// Start torrent because it was added in paused state
|
|
|
|
|
h.resume(); |
|
|
|
|
} |
|
|
|
|
// If download from url, remove temp file
|
|
|
|
|
if(!from_url.isNull()) QFile::remove(file); |
|
|
|
|
// Delete from scan dir to avoid trying to download it again
|
|
|
|
|
if(fromScanDir) { |
|
|
|
|
QFile::remove(file); |
|
|
|
|
QFile::remove(file); |
|
|
|
|
} |
|
|
|
|
// Send torrent addition signal
|
|
|
|
|
if(!from_url.isNull()) { |
|
|
|
|
if(fastResume) |
|
|
|
|
addConsoleMessage(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(from_url)); |
|
|
|
|
else |
|
|
|
|
addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(from_url)); |
|
|
|
|
if(fastResume) |
|
|
|
|
addConsoleMessage(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(from_url)); |
|
|
|
|
else |
|
|
|
|
addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(from_url)); |
|
|
|
|
}else{ |
|
|
|
|
if(fastResume) |
|
|
|
|
addConsoleMessage(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(file)); |
|
|
|
|
else |
|
|
|
|
addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(file)); |
|
|
|
|
if(fastResume) |
|
|
|
|
addConsoleMessage(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(file)); |
|
|
|
|
else |
|
|
|
|
addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(file)); |
|
|
|
|
} |
|
|
|
|
emit addedTorrent(h); |
|
|
|
|
return h; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check in .priorities file if the user filtered files
|
|
|
|
|
// in this torrent.
|
|
|
|
|
// Check if the user filtered files in this torrent.
|
|
|
|
|
bool bittorrent::has_filtered_files(QString hash) const{ |
|
|
|
|
QFile pieces_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".priorities"); |
|
|
|
|
// Read saved file
|
|
|
|
|
if(!pieces_file.open(QIODevice::ReadOnly | QIODevice::Text)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
QByteArray pieces_text = pieces_file.readAll(); |
|
|
|
|
pieces_file.close(); |
|
|
|
|
QList<QByteArray> pieces_priorities_list = pieces_text.split('\n'); |
|
|
|
|
unsigned int listSize = pieces_priorities_list.size(); |
|
|
|
|
for(unsigned int i=0; i<listSize-1; ++i) { |
|
|
|
|
int priority = pieces_priorities_list.at(i).toInt(); |
|
|
|
|
QVariantList files_priority = TorrentPersistentData::getFilesPriority(hash); |
|
|
|
|
foreach(QVariant var_prio, files_priority) { |
|
|
|
|
int priority = var_prio.toInt(); |
|
|
|
|
if( priority < 0 || priority > 7) { |
|
|
|
|
priority = 1; |
|
|
|
|
} |
|
|
|
|
if(!priority) { |
|
|
|
|
if(!priority) |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
@ -648,21 +639,21 @@ void bittorrent::enableLSD(bool b) {
@@ -648,21 +639,21 @@ void bittorrent::enableLSD(bool b) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::loadSessionState() { |
|
|
|
|
boost::filesystem::ifstream ses_state_file((misc::qBittorrentPath()+QString::fromUtf8("ses_state")).toLocal8Bit().data() |
|
|
|
|
, std::ios_base::binary); |
|
|
|
|
ses_state_file.unsetf(std::ios_base::skipws); |
|
|
|
|
s->load_state(bdecode( |
|
|
|
|
std::istream_iterator<char>(ses_state_file) |
|
|
|
|
, std::istream_iterator<char>())); |
|
|
|
|
boost::filesystem::ifstream ses_state_file((misc::qBittorrentPath()+QString::fromUtf8("ses_state")).toLocal8Bit().data() |
|
|
|
|
, std::ios_base::binary); |
|
|
|
|
ses_state_file.unsetf(std::ios_base::skipws); |
|
|
|
|
s->load_state(bdecode( |
|
|
|
|
std::istream_iterator<char>(ses_state_file) |
|
|
|
|
, std::istream_iterator<char>())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::saveSessionState() { |
|
|
|
|
qDebug("Saving session state to disk..."); |
|
|
|
|
entry session_state = s->state(); |
|
|
|
|
boost::filesystem::ofstream out((misc::qBittorrentPath()+QString::fromUtf8("ses_state")).toLocal8Bit().data() |
|
|
|
|
, std::ios_base::binary); |
|
|
|
|
out.unsetf(std::ios_base::skipws); |
|
|
|
|
bencode(std::ostream_iterator<char>(out), session_state); |
|
|
|
|
qDebug("Saving session state to disk..."); |
|
|
|
|
entry session_state = s->state(); |
|
|
|
|
boost::filesystem::ofstream out((misc::qBittorrentPath()+QString::fromUtf8("ses_state")).toLocal8Bit().data() |
|
|
|
|
, std::ios_base::binary); |
|
|
|
|
out.unsetf(std::ios_base::skipws); |
|
|
|
|
bencode(std::ostream_iterator<char>(out), session_state); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Enable DHT
|
|
|
|
@ -677,18 +668,18 @@ bool bittorrent::enableDHT(bool b) {
@@ -677,18 +668,18 @@ bool bittorrent::enableDHT(bool b) {
|
|
|
|
|
try{ |
|
|
|
|
dht_state = bdecode(std::istream_iterator<char>(dht_state_file), std::istream_iterator<char>()); |
|
|
|
|
}catch (std::exception&) {} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
try { |
|
|
|
|
s->start_dht(dht_state); |
|
|
|
|
s->add_dht_router(std::make_pair(std::string("router.bittorrent.com"), 6881)); |
|
|
|
|
s->add_dht_router(std::make_pair(std::string("router.utorrent.com"), 6881)); |
|
|
|
|
s->add_dht_router(std::make_pair(std::string("router.bitcomet.com"), 6881)); |
|
|
|
|
DHTEnabled = true; |
|
|
|
|
qDebug("DHT enabled"); |
|
|
|
|
}catch(std::exception e) { |
|
|
|
|
qDebug("Could not enable DHT, reason: %s", e.what()); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
s->start_dht(dht_state); |
|
|
|
|
s->add_dht_router(std::make_pair(std::string("router.bittorrent.com"), 6881)); |
|
|
|
|
s->add_dht_router(std::make_pair(std::string("router.utorrent.com"), 6881)); |
|
|
|
|
s->add_dht_router(std::make_pair(std::string("router.bitcomet.com"), 6881)); |
|
|
|
|
DHTEnabled = true; |
|
|
|
|
qDebug("DHT enabled"); |
|
|
|
|
}catch(std::exception e) { |
|
|
|
|
qDebug("Could not enable DHT, reason: %s", e.what()); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if(DHTEnabled) { |
|
|
|
@ -715,7 +706,7 @@ void bittorrent::saveTorrentSpeedLimits(QString hash) {
@@ -715,7 +706,7 @@ void bittorrent::saveTorrentSpeedLimits(QString hash) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::loadTorrentSpeedLimits(QString hash) { |
|
|
|
|
// qDebug("Loading speedLimits file for %s", hash.toLocal8Bit().data());
|
|
|
|
|
// qDebug("Loading speedLimits file for %s", hash.toLocal8Bit().data());
|
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
QFile speeds_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".speedLimits"); |
|
|
|
|
if(!speeds_file.open(QIODevice::ReadOnly | QIODevice::Text)) { |
|
|
|
@ -732,7 +723,7 @@ void bittorrent::loadTorrentSpeedLimits(QString hash) {
@@ -732,7 +723,7 @@ void bittorrent::loadTorrentSpeedLimits(QString hash) {
|
|
|
|
|
h.set_upload_limit(speeds.at(1).toInt()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Read pieces priorities from .priorities file
|
|
|
|
|
// Read pieces priorities from hard disk
|
|
|
|
|
// and ask QTorrentHandle to consider them
|
|
|
|
|
void bittorrent::loadFilesPriorities(QTorrentHandle &h) { |
|
|
|
|
qDebug("Applying pieces priorities"); |
|
|
|
@ -740,31 +731,19 @@ void bittorrent::loadFilesPriorities(QTorrentHandle &h) {
@@ -740,31 +731,19 @@ void bittorrent::loadFilesPriorities(QTorrentHandle &h) {
|
|
|
|
|
qDebug("/!\\ Error: Invalid handle"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
unsigned int nbFiles = h.num_files(); |
|
|
|
|
QString hash = h.hash(); |
|
|
|
|
QFile pieces_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".priorities"); |
|
|
|
|
if(!pieces_file.exists()){ |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// Read saved file
|
|
|
|
|
if(!pieces_file.open(QIODevice::ReadOnly | QIODevice::Text)) { |
|
|
|
|
qDebug("* Error: Couldn't open priorities file: %s", hash.toLocal8Bit().data()); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
QByteArray pieces_priorities = pieces_file.readAll(); |
|
|
|
|
pieces_file.close(); |
|
|
|
|
QList<QByteArray> pieces_priorities_list = pieces_priorities.split('\n'); |
|
|
|
|
if((unsigned int)pieces_priorities_list.size() != nbFiles+1) { |
|
|
|
|
std::cerr << "* Error: Corrupted priorities file\n"; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
std::vector<int> v; |
|
|
|
|
for(unsigned int i=0; i<nbFiles; ++i) { |
|
|
|
|
int priority = pieces_priorities_list.at(i).toInt(); |
|
|
|
|
QVariantList files_priority; |
|
|
|
|
if(TorrentTempData::hasTempData(h.hash())) { |
|
|
|
|
files_priority = TorrentTempData::getFilesPriority(h.hash()); |
|
|
|
|
} else { |
|
|
|
|
files_priority = TorrentPersistentData::getFilesPriority(h.hash()); |
|
|
|
|
} |
|
|
|
|
foreach(const QVariant &var_prio, files_priority) { |
|
|
|
|
int priority = var_prio.toInt(); |
|
|
|
|
if( priority < 0 || priority > 7) { |
|
|
|
|
priority = 1; |
|
|
|
|
} |
|
|
|
|
qDebug("Setting piece piority to %d", priority); |
|
|
|
|
qDebug("Setting file piority to %d", priority); |
|
|
|
|
v.push_back(priority); |
|
|
|
|
} |
|
|
|
|
h.prioritize_files(v); |
|
|
|
@ -800,47 +779,47 @@ void bittorrent::saveFastResumeData() {
@@ -800,47 +779,47 @@ void bittorrent::saveFastResumeData() {
|
|
|
|
|
QTorrentHandle h = QTorrentHandle(*torrentIT); |
|
|
|
|
if(!h.is_valid() || !h.has_metadata()) continue; |
|
|
|
|
if(isQueueingEnabled()) |
|
|
|
|
saveTorrentPriority(h.hash(), h.queue_position()); |
|
|
|
|
TorrentPersistentData::savePriority(h); |
|
|
|
|
if(h.is_paused()) continue; |
|
|
|
|
if(h.state() == torrent_status::checking_files || h.state() == torrent_status::queued_for_checking) continue; |
|
|
|
|
h.save_resume_data(); |
|
|
|
|
++num_resume_data; |
|
|
|
|
} |
|
|
|
|
while (num_resume_data > 0) { |
|
|
|
|
alert const* a = s->wait_for_alert(seconds(30)); |
|
|
|
|
if (a == 0) { |
|
|
|
|
std::cerr << " aborting with " << num_resume_data << " outstanding " |
|
|
|
|
"torrents to save resume data for" << std::endl; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
// Saving fastresume data can fail
|
|
|
|
|
save_resume_data_failed_alert const* rda = dynamic_cast<save_resume_data_failed_alert const*>(a); |
|
|
|
|
if (rda) { |
|
|
|
|
--num_resume_data; |
|
|
|
|
s->pop_alert(); |
|
|
|
|
// Remove torrent from session
|
|
|
|
|
s->remove_torrent(rda->handle); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
save_resume_data_alert const* rd = dynamic_cast<save_resume_data_alert const*>(a); |
|
|
|
|
if (!rd) { |
|
|
|
|
s->pop_alert(); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
// Saving fast resume data was successful
|
|
|
|
|
alert const* a = s->wait_for_alert(seconds(30)); |
|
|
|
|
if (a == 0) { |
|
|
|
|
std::cerr << " aborting with " << num_resume_data << " outstanding " |
|
|
|
|
"torrents to save resume data for" << std::endl; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
// Saving fastresume data can fail
|
|
|
|
|
save_resume_data_failed_alert const* rda = dynamic_cast<save_resume_data_failed_alert const*>(a); |
|
|
|
|
if (rda) { |
|
|
|
|
--num_resume_data; |
|
|
|
|
if (!rd->resume_data) continue; |
|
|
|
|
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); |
|
|
|
|
QTorrentHandle h(rd->handle); |
|
|
|
|
// Remove old fastresume file if it exists
|
|
|
|
|
QFile::remove(torrentBackup.path()+QDir::separator()+ h.hash() + ".fastresume"); |
|
|
|
|
QString file = h.hash()+".fastresume"; |
|
|
|
|
boost::filesystem::ofstream out(fs::path(torrentBackup.path().toLocal8Bit().data()) / file.toLocal8Bit().data(), std::ios_base::binary); |
|
|
|
|
out.unsetf(std::ios_base::skipws); |
|
|
|
|
bencode(std::ostream_iterator<char>(out), *rd->resume_data); |
|
|
|
|
s->pop_alert(); |
|
|
|
|
// Remove torrent from session
|
|
|
|
|
s->remove_torrent(rd->handle); |
|
|
|
|
s->remove_torrent(rda->handle); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
save_resume_data_alert const* rd = dynamic_cast<save_resume_data_alert const*>(a); |
|
|
|
|
if (!rd) { |
|
|
|
|
s->pop_alert(); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
// Saving fast resume data was successful
|
|
|
|
|
--num_resume_data; |
|
|
|
|
if (!rd->resume_data) continue; |
|
|
|
|
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); |
|
|
|
|
QTorrentHandle h(rd->handle); |
|
|
|
|
// Remove old fastresume file if it exists
|
|
|
|
|
QFile::remove(torrentBackup.path()+QDir::separator()+ h.hash() + ".fastresume"); |
|
|
|
|
QString file = h.hash()+".fastresume"; |
|
|
|
|
boost::filesystem::ofstream out(fs::path(torrentBackup.path().toLocal8Bit().data()) / file.toLocal8Bit().data(), std::ios_base::binary); |
|
|
|
|
out.unsetf(std::ios_base::skipws); |
|
|
|
|
bencode(std::ostream_iterator<char>(out), *rd->resume_data); |
|
|
|
|
// Remove torrent from session
|
|
|
|
|
s->remove_torrent(rd->handle); |
|
|
|
|
s->pop_alert(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -896,14 +875,14 @@ void bittorrent::scanDirectory(QString scan_dir) {
@@ -896,14 +875,14 @@ void bittorrent::scanDirectory(QString scan_dir) {
|
|
|
|
|
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); |
|
|
|
|
if(torrent.size() != 0) { |
|
|
|
|
qDebug("Adding for scan_dir: %s", fullPath.toLocal8Bit().data()); |
|
|
|
|
addTorrent(fullPath, true); |
|
|
|
|
} else { |
|
|
|
|
qDebug("Ignoring empty file: %s", fullPath.toLocal8Bit().data()); |
|
|
|
|
} |
|
|
|
|
QString fullPath = dir.path()+QDir::separator()+file; |
|
|
|
|
QFile torrent(fullPath); |
|
|
|
|
if(torrent.size() != 0) { |
|
|
|
|
qDebug("Adding for scan_dir: %s", fullPath.toLocal8Bit().data()); |
|
|
|
|
addTorrent(fullPath, true); |
|
|
|
|
} else { |
|
|
|
|
qDebug("Ignoring empty file: %s", fullPath.toLocal8Bit().data()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
FSMutex->unlock(); |
|
|
|
|
} |
|
|
|
@ -912,6 +891,10 @@ void bittorrent::setDefaultSavePath(QString savepath) {
@@ -912,6 +891,10 @@ void bittorrent::setDefaultSavePath(QString savepath) {
|
|
|
|
|
defaultSavePath = savepath; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool bittorrent::useTemporaryFolder() const { |
|
|
|
|
return !defaultTempPath.isEmpty(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::setDefaultTempPath(QString temppath) { |
|
|
|
|
if(defaultTempPath == temppath) |
|
|
|
|
return; |
|
|
|
@ -938,23 +921,28 @@ void bittorrent::setDefaultTempPath(QString temppath) {
@@ -938,23 +921,28 @@ void bittorrent::setDefaultTempPath(QString temppath) {
|
|
|
|
|
defaultTempPath = temppath; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::saveTrackerFile(QString hash) { |
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
TorrentPersistentData::saveTrackers(h); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Enable directory scanning
|
|
|
|
|
void bittorrent::enableDirectoryScanning(QString scan_dir) { |
|
|
|
|
if(!scan_dir.isEmpty()) { |
|
|
|
|
if(FSWatcher == 0) { |
|
|
|
|
FSMutex = new QMutex(); |
|
|
|
|
FSWatcher = new QFileSystemWatcher(QStringList(scan_dir), this); |
|
|
|
|
connect(FSWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(scanDirectory(QString))); |
|
|
|
|
FSMutex = new QMutex(); |
|
|
|
|
FSWatcher = new QFileSystemWatcher(QStringList(scan_dir), this); |
|
|
|
|
connect(FSWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(scanDirectory(QString))); |
|
|
|
|
// Initial scan
|
|
|
|
|
scanDirectory(scan_dir); |
|
|
|
|
} else { |
|
|
|
|
QString old_scan_dir = FSWatcher->directories().first(); |
|
|
|
|
if(old_scan_dir != scan_dir) { |
|
|
|
|
FSWatcher->removePath(old_scan_dir); |
|
|
|
|
FSWatcher->addPath(scan_dir); |
|
|
|
|
// Initial scan
|
|
|
|
|
scanDirectory(scan_dir); |
|
|
|
|
} else { |
|
|
|
|
QString old_scan_dir = FSWatcher->directories().first(); |
|
|
|
|
if(old_scan_dir != scan_dir) { |
|
|
|
|
FSWatcher->removePath(old_scan_dir); |
|
|
|
|
FSWatcher->addPath(scan_dir); |
|
|
|
|
// Initial scan
|
|
|
|
|
scanDirectory(scan_dir); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -962,8 +950,8 @@ void bittorrent::enableDirectoryScanning(QString scan_dir) {
@@ -962,8 +950,8 @@ void bittorrent::enableDirectoryScanning(QString scan_dir) {
|
|
|
|
|
// Disable directory scanning
|
|
|
|
|
void bittorrent::disableDirectoryScanning() { |
|
|
|
|
if(FSWatcher) { |
|
|
|
|
delete FSWatcher; |
|
|
|
|
delete FSMutex; |
|
|
|
|
delete FSWatcher; |
|
|
|
|
delete FSMutex; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1032,46 +1020,21 @@ void bittorrent::setDeleteRatio(float ratio) {
@@ -1032,46 +1020,21 @@ void bittorrent::setDeleteRatio(float ratio) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool bittorrent::loadTrackerFile(QString hash) { |
|
|
|
|
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); |
|
|
|
|
QFile tracker_file(torrentBackup.path()+QDir::separator()+ hash + ".trackers"); |
|
|
|
|
if(!tracker_file.exists()) return false; |
|
|
|
|
tracker_file.open(QIODevice::ReadOnly | QIODevice::Text); |
|
|
|
|
QStringList lines = QString::fromUtf8(tracker_file.readAll().data()).split("\n"); |
|
|
|
|
void bittorrent::loadTrackerFile(QString hash) { |
|
|
|
|
QHash<QString, QVariant> tiers = TorrentPersistentData::getTrackers(hash); |
|
|
|
|
std::vector<announce_entry> trackers; |
|
|
|
|
foreach(const QString &line, lines) { |
|
|
|
|
QStringList parts = line.split("|"); |
|
|
|
|
if(parts.size() != 2) continue; |
|
|
|
|
announce_entry t(parts[0].toStdString()); |
|
|
|
|
t.tier = parts[1].toInt(); |
|
|
|
|
foreach(const QString tracker_url, tiers.keys()) { |
|
|
|
|
announce_entry t(tracker_url.toStdString()); |
|
|
|
|
t.tier = tiers[tracker_url].toInt(); |
|
|
|
|
trackers.push_back(t); |
|
|
|
|
} |
|
|
|
|
if(!trackers.empty()) { |
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
h.replace_trackers(trackers); |
|
|
|
|
h.force_reannounce(); |
|
|
|
|
return true; |
|
|
|
|
}else{ |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::saveTrackerFile(QString hash) { |
|
|
|
|
qDebug("Saving tracker file for %s", hash.toLocal8Bit().data()); |
|
|
|
|
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); |
|
|
|
|
QFile tracker_file(torrentBackup.path()+QDir::separator()+ hash + ".trackers"); |
|
|
|
|
if(tracker_file.exists()) { |
|
|
|
|
tracker_file.remove(); |
|
|
|
|
} |
|
|
|
|
tracker_file.open(QIODevice::WriteOnly | QIODevice::Text); |
|
|
|
|
QTorrentHandle h = getTorrentHandle(hash); |
|
|
|
|
std::vector<announce_entry> trackers = h.trackers(); |
|
|
|
|
for(unsigned int i=0; i<trackers.size(); ++i) { |
|
|
|
|
tracker_file.write(QByteArray(trackers[i].url.c_str())+QByteArray("|")+QByteArray(misc::toString(i).c_str())+QByteArray("\n")); |
|
|
|
|
} |
|
|
|
|
tracker_file.close(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Set DHT port (>= 1000 or 0 if same as BT)
|
|
|
|
|
void bittorrent::setDHTPort(int dht_port) { |
|
|
|
|
if(dht_port == 0 or dht_port >= 1000) { |
|
|
|
@ -1149,10 +1112,8 @@ void bittorrent::readAlerts() {
@@ -1149,10 +1112,8 @@ void bittorrent::readAlerts() {
|
|
|
|
|
if(h.is_valid()){ |
|
|
|
|
emit finishedTorrent(h); |
|
|
|
|
QString hash = h.hash(); |
|
|
|
|
// Create .finished file if necessary
|
|
|
|
|
QFile finished_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".finished"); |
|
|
|
|
finished_file.open(QIODevice::WriteOnly | QIODevice::Text); |
|
|
|
|
finished_file.close(); |
|
|
|
|
// Remember finished state
|
|
|
|
|
TorrentPersistentData::saveSeedStatus(h); |
|
|
|
|
// Move to download directory if necessary
|
|
|
|
|
if(!defaultTempPath.isEmpty()) { |
|
|
|
|
// Check if directory is different
|
|
|
|
@ -1167,19 +1128,19 @@ void bittorrent::readAlerts() {
@@ -1167,19 +1128,19 @@ void bittorrent::readAlerts() {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if (save_resume_data_alert* p = dynamic_cast<save_resume_data_alert*>(a.get())) { |
|
|
|
|
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); |
|
|
|
|
QTorrentHandle h(p->handle); |
|
|
|
|
QString file = h.hash()+".fastresume"; |
|
|
|
|
// Delete old fastresume file if necessary
|
|
|
|
|
if(QFile::exists(file)) |
|
|
|
|
QFile::remove(file); |
|
|
|
|
qDebug("Saving fastresume data in %s", file.toLocal8Bit().data()); |
|
|
|
|
if (p->resume_data) |
|
|
|
|
{ |
|
|
|
|
boost::filesystem::ofstream out(fs::path(torrentBackup.path().toLocal8Bit().data()) / file.toLocal8Bit().data(), std::ios_base::binary); |
|
|
|
|
out.unsetf(std::ios_base::skipws); |
|
|
|
|
bencode(std::ostream_iterator<char>(out), *p->resume_data); |
|
|
|
|
} |
|
|
|
|
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); |
|
|
|
|
QTorrentHandle h(p->handle); |
|
|
|
|
QString file = h.hash()+".fastresume"; |
|
|
|
|
// Delete old fastresume file if necessary
|
|
|
|
|
if(QFile::exists(file)) |
|
|
|
|
QFile::remove(file); |
|
|
|
|
qDebug("Saving fastresume data in %s", file.toLocal8Bit().data()); |
|
|
|
|
if (p->resume_data) |
|
|
|
|
{ |
|
|
|
|
boost::filesystem::ofstream out(fs::path(torrentBackup.path().toLocal8Bit().data()) / file.toLocal8Bit().data(), std::ios_base::binary); |
|
|
|
|
out.unsetf(std::ios_base::skipws); |
|
|
|
|
bencode(std::ostream_iterator<char>(out), *p->resume_data); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if (file_error_alert* p = dynamic_cast<file_error_alert*>(a.get())) { |
|
|
|
|
QTorrentHandle h(p->handle); |
|
|
|
@ -1284,17 +1245,17 @@ session_status bittorrent::getSessionStatus() const{
@@ -1284,17 +1245,17 @@ session_status bittorrent::getSessionStatus() const{
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QString bittorrent::getSavePath(QString hash) { |
|
|
|
|
QFile savepath_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".savepath"); |
|
|
|
|
QByteArray line; |
|
|
|
|
QString savePath; |
|
|
|
|
if(savepath_file.open(QIODevice::ReadOnly | QIODevice::Text)) { |
|
|
|
|
line = savepath_file.readAll(); |
|
|
|
|
savepath_file.close(); |
|
|
|
|
qDebug(" -> Save path: %s", line.data()); |
|
|
|
|
savePath = QString::fromUtf8(line.data()); |
|
|
|
|
}else{ |
|
|
|
|
// use default save path
|
|
|
|
|
qDebug("Using default save path because none was set"); |
|
|
|
|
if(TorrentTempData::hasTempData(hash)) { |
|
|
|
|
savePath = TorrentTempData::getSavePath(hash); |
|
|
|
|
qDebug("getSavePath, got save_path from temp data: %s", savePath.toUtf8().data()); |
|
|
|
|
} else { |
|
|
|
|
savePath = TorrentPersistentData::getSavePath(hash); |
|
|
|
|
qDebug("getSavePath, got save_path from persistent data: %s", savePath.toUtf8().data()); |
|
|
|
|
} |
|
|
|
|
if(savePath.isEmpty()) { |
|
|
|
|
// use default save path if no other can be found
|
|
|
|
|
qDebug("Using default save path because none was set: %s", defaultSavePath.toUtf8().data()); |
|
|
|
|
savePath = defaultSavePath; |
|
|
|
|
} |
|
|
|
|
// Checking if savePath Dir exists
|
|
|
|
@ -1383,58 +1344,39 @@ void bittorrent::applyEncryptionSettings(pe_settings se) {
@@ -1383,58 +1344,39 @@ void bittorrent::applyEncryptionSettings(pe_settings se) {
|
|
|
|
|
s->set_pe_settings(se); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void bittorrent::saveTorrentPriority(QString hash, int prio) { |
|
|
|
|
// Write .queued file
|
|
|
|
|
QFile prio_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".prio"); |
|
|
|
|
prio_file.open(QIODevice::WriteOnly | QIODevice::Text); |
|
|
|
|
prio_file.write(QByteArray::number(prio)); |
|
|
|
|
prio_file.close(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Will fast resume torrents in
|
|
|
|
|
// backup directory
|
|
|
|
|
void bittorrent::resumeUnfinishedTorrents() { |
|
|
|
|
void bittorrent::startUpTorrents() { |
|
|
|
|
qDebug("Resuming unfinished torrents"); |
|
|
|
|
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); |
|
|
|
|
QStringList fileNames; |
|
|
|
|
// Scan torrentBackup directory
|
|
|
|
|
QStringList filters; |
|
|
|
|
filters << "*.torrent"; |
|
|
|
|
fileNames = torrentBackup.entryList(filters, QDir::Files, QDir::Unsorted); |
|
|
|
|
QStringList known_torrents = TorrentPersistentData::knownTorrents(); |
|
|
|
|
if(isQueueingEnabled()) { |
|
|
|
|
QList<QPair<int, QString> > filePaths; |
|
|
|
|
foreach(const QString &fileName, fileNames) { |
|
|
|
|
QString filePath = torrentBackup.path()+QDir::separator()+fileName; |
|
|
|
|
int prio = 99999; |
|
|
|
|
// Get priority
|
|
|
|
|
QString prioPath = filePath; |
|
|
|
|
prioPath.replace(".torrent", ".prio"); |
|
|
|
|
if(QFile::exists(prioPath)) { |
|
|
|
|
QFile prio_file(prioPath); |
|
|
|
|
if(prio_file.open(QIODevice::ReadOnly | QIODevice::Text)) { |
|
|
|
|
bool ok = false; |
|
|
|
|
prio = prio_file.readAll().toInt(&ok); |
|
|
|
|
if(!ok) |
|
|
|
|
prio = 99999; |
|
|
|
|
prio_file.close(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
misc::insertSort2<QString>(filePaths, qMakePair(prio, filePath)); |
|
|
|
|
} |
|
|
|
|
// Resume downloads
|
|
|
|
|
QPair<int, QString> fileName; |
|
|
|
|
foreach(fileName, filePaths) { |
|
|
|
|
addTorrent(fileName.second, false, QString(), true); |
|
|
|
|
QList<QPair<int, QString> > filePaths; |
|
|
|
|
foreach(const QString &hash, known_torrents) { |
|
|
|
|
QString filePath; |
|
|
|
|
if(TorrentPersistentData::isMagnet(hash)) { |
|
|
|
|
filePath = TorrentPersistentData::getMagnetUri(hash); |
|
|
|
|
} else { |
|
|
|
|
filePath = torrentBackup.path()+QDir::separator()+hash+".torrent"; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
QStringList filePaths; |
|
|
|
|
foreach(const QString &fileName, fileNames) { |
|
|
|
|
filePaths.append(torrentBackup.path()+QDir::separator()+fileName); |
|
|
|
|
} |
|
|
|
|
// Resume downloads
|
|
|
|
|
foreach(const QString &fileName, filePaths) { |
|
|
|
|
addTorrent(fileName, false, QString(), true); |
|
|
|
|
} |
|
|
|
|
int prio = TorrentPersistentData::getPriority(hash); |
|
|
|
|
misc::insertSort2<QString>(filePaths, qMakePair(prio, filePath)); |
|
|
|
|
} |
|
|
|
|
// Resume downloads
|
|
|
|
|
QPair<int, QString> fileName; |
|
|
|
|
foreach(fileName, filePaths) { |
|
|
|
|
addTorrent(fileName.second, false, QString(), true); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
QStringList filePaths; |
|
|
|
|
foreach(const QString &fileName, fileNames) { |
|
|
|
|
filePaths.append(torrentBackup.path()+QDir::separator()+fileName); |
|
|
|
|
} |
|
|
|
|
// Resume downloads
|
|
|
|
|
foreach(const QString &fileName, filePaths) { |
|
|
|
|
addTorrent(fileName, false, QString(), true); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
qDebug("Unfinished torrents resumed"); |
|
|
|
|
} |
|
|
|
|