Browse Source

- Rewrited torrent resume code to make it cleaner and more generic

* magnet URI support should be easy to implement now
Warning: Since a lot of code was rewrited, some bugs may have been introduced
adaptive-webui-19844
Christophe Dumez 15 years ago
parent
commit
2742a54d6e
  1. 3
      Changelog
  2. 2233
      src/GUI.cpp
  3. 6
      src/arborescence.h
  4. 702
      src/bittorrent.cpp
  5. 10
      src/bittorrent.h
  6. 118
      src/properties_imp.cpp
  7. 4
      src/properties_imp.h
  8. 15
      src/qtorrenthandle.cpp
  9. 3
      src/qtorrenthandle.h
  10. 28
      src/torrentAddition.h
  11. 339
      src/torrentPersistentData.h

3
Changelog

@ -1,3 +1,6 @@
* Unknown - Christophe Dumez <chris@qbittorrent.org> - v1.5.0
- BUGFIX: torrent resume code rewrited
* Thu Aug 13 2009 - Christophe Dumez <chris@qbittorrent.org> - v1.4.0 * Thu Aug 13 2009 - Christophe Dumez <chris@qbittorrent.org> - v1.4.0
- FEATURE: Display swarm information in lists - FEATURE: Display swarm information in lists
- FEATURE: Allow to define temporary download folder - FEATURE: Allow to define temporary download folder

2233
src/GUI.cpp

File diff suppressed because it is too large Load Diff

6
src/arborescence.h

@ -199,7 +199,7 @@ class arborescence {
Q_ASSERT(root->getSize() == t->total_size()); Q_ASSERT(root->getSize() == t->total_size());
} }
arborescence(torrent_info const& t, std::vector<size_type> fp, int *prioritiesTab) { arborescence(torrent_info const& t, std::vector<size_type> fp, std::vector<int> files_priority) {
torrent_info::file_iterator fi = t.begin_files(); torrent_info::file_iterator fi = t.begin_files();
if(t.num_files() > 1) { if(t.num_files() > 1) {
qDebug("More than one file in the torrent, setting a folder as root"); qDebug("More than one file in the torrent, setting a folder as root");
@ -207,13 +207,13 @@ class arborescence {
} else { } else {
// XXX: Will crash if there is no file in torrent // XXX: Will crash if there is no file in torrent
qDebug("one file in the torrent, setting it as root with index 0"); qDebug("one file in the torrent, setting it as root with index 0");
root = new torrent_file(0, misc::toQString(t.name()), false, fi->size, 0, ((double)fp[0])/t.file_at(0).size, prioritiesTab[0]); root = new torrent_file(0, misc::toQString(t.name()), false, fi->size, 0, ((double)fp[0])/t.file_at(0).size, files_priority.at(0));
return; return;
} }
int i = 0; int i = 0;
while(fi != t.end_files()) { while(fi != t.end_files()) {
QString path = QDir::cleanPath(misc::toQString(fi->path.string())); QString path = QDir::cleanPath(misc::toQString(fi->path.string()));
addFile(path, fi->size, i, ((double)fp[i])/t.file_at(i).size, prioritiesTab[i]); addFile(path, fi->size, i, ((double)fp[i])/t.file_at(i).size, files_priority.at(i));
fi++; fi++;
++i; ++i;
} }

702
src/bittorrent.cpp

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

10
src/bittorrent.h

@ -107,6 +107,7 @@ class bittorrent : public QObject {
QStringList getConsoleMessages() const; QStringList getConsoleMessages() const;
QStringList getPeerBanMessages() const; QStringList getPeerBanMessages() const;
qlonglong getETA(QString hash) const; qlonglong getETA(QString hash) const;
bool useTemporaryFolder() const;
public slots: public slots:
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false); QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false);
@ -115,11 +116,12 @@ class bittorrent : public QObject {
void downloadFromUrl(QString url); void downloadFromUrl(QString url);
void downloadFromURLList(const QStringList& url_list); void downloadFromURLList(const QStringList& url_list);
void deleteTorrent(QString hash, bool permanent = false); void deleteTorrent(QString hash, bool permanent = false);
void startUpTorrents();
/* Needed by Web UI */ /* Needed by Web UI */
void pauseAllTorrents(); void pauseAllTorrents();
void resumeAllTorrents();
void pauseTorrent(QString hash); void pauseTorrent(QString hash);
void resumeTorrent(QString hash); void resumeTorrent(QString hash);
void resumeAllTorrents();
/* End Web UI */ /* End Web UI */
void saveDHTEntry(); void saveDHTEntry();
void preAllocateAllFiles(bool b); void preAllocateAllFiles(bool b);
@ -129,8 +131,6 @@ class bittorrent : public QObject {
void enableIPFilter(QString filter); void enableIPFilter(QString filter);
void disableIPFilter(); void disableIPFilter();
void setQueueingEnabled(bool enable); void setQueueingEnabled(bool enable);
void resumeUnfinishedTorrents();
void saveTorrentPriority(QString hash, int prio);
void saveTorrentSpeedLimits(QString hash); void saveTorrentSpeedLimits(QString hash);
void loadTorrentSpeedLimits(QString hash); void loadTorrentSpeedLimits(QString hash);
void handleDownloadFailure(QString url, QString reason); void handleDownloadFailure(QString url, QString reason);
@ -164,12 +164,12 @@ class bittorrent : public QObject {
void addConsoleMessage(QString msg, QColor color=QApplication::palette().color(QPalette::WindowText)); void addConsoleMessage(QString msg, QColor color=QApplication::palette().color(QPalette::WindowText));
void addPeerBanMessage(QString msg, bool from_ipfilter); void addPeerBanMessage(QString msg, bool from_ipfilter);
void processDownloadedFile(QString, QString); void processDownloadedFile(QString, QString);
void saveTrackerFile(QString hash);
protected slots: protected slots:
void scanDirectory(QString); void scanDirectory(QString);
void readAlerts(); void readAlerts();
bool loadTrackerFile(QString hash); void loadTrackerFile(QString hash);
void saveTrackerFile(QString hash);
void deleteBigRatios(); void deleteBigRatios();
signals: signals:

118
src/properties_imp.cpp

@ -36,6 +36,7 @@
#include "realprogressbar.h" #include "realprogressbar.h"
#include "realprogressbarthread.h" #include "realprogressbarthread.h"
#include "TrackersAdditionDlg.h" #include "TrackersAdditionDlg.h"
#include "torrentPersistentData.h"
#include <QInputDialog> #include <QInputDialog>
#include <QMessageBox> #include <QMessageBox>
@ -86,7 +87,7 @@ properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h
// get Infos from torrent handle // get Infos from torrent handle
fileName->setText(h.name()); fileName->setText(h.name());
// Torrent Infos // Torrent Infos
save_path->setText(h.save_path()); save_path->setText(TorrentPersistentData::getSavePath(hash));
QString author = h.creator().trimmed(); QString author = h.creator().trimmed();
if(author.isEmpty()) if(author.isEmpty())
author = tr("Unknown"); author = tr("Unknown");
@ -115,23 +116,18 @@ properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h
shareRatio->setText(QString(QByteArray::number(ratio, 'f', 1))); shareRatio->setText(QString(QByteArray::number(ratio, 'f', 1)));
std::vector<size_type> fp; std::vector<size_type> fp;
h.file_progress(fp); h.file_progress(fp);
int *prioritiesTab = loadPiecesPriorities(); std::vector<int> files_priority = loadFilesPriorities();
// List files in torrent // List files in torrent
arborescence *arb = new arborescence(h.get_torrent_info(), fp, prioritiesTab); arborescence *arb = new arborescence(h.get_torrent_info(), fp, files_priority);
addFilesToTree(arb->getRoot(), PropListModel->invisibleRootItem()); addFilesToTree(arb->getRoot(), PropListModel->invisibleRootItem());
delete arb; delete arb;
delete prioritiesTab;
connect(PropListModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(updatePriorities(QStandardItem*))); connect(PropListModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(updatePriorities(QStandardItem*)));
filesList->expandAll(); filesList->expandAll();
// List web seeds // List web seeds
loadWebSeedsFromFile(); loadWebSeedsFromFile();
loadWebSeeds(); loadWebSeeds();
// Incremental download // Incremental download
if(QFile::exists(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".incremental")){ incrementalDownload->setChecked(TorrentPersistentData::isSequentialDownload(hash));
incrementalDownload->setChecked(true);
}else{
incrementalDownload->setChecked(false);
}
updateInfosTimer = new QTimer(this); updateInfosTimer = new QTimer(this);
connect(updateInfosTimer, SIGNAL(timeout()), this, SLOT(updateInfos())); connect(updateInfosTimer, SIGNAL(timeout()), this, SLOT(updateInfos()));
updateInfosTimer->start(3000); updateInfosTimer->start(3000);
@ -314,41 +310,19 @@ void properties::loadWebSeeds(){
} }
} }
int* properties::loadPiecesPriorities(){ std::vector<int> properties::loadFilesPriorities(){
unsigned int nbFiles = h.num_files(); std::vector<int> fp;
int *prioritiesTab = new int[nbFiles]; QVariantList files_priority = TorrentPersistentData::getFilesPriority(hash);
QString fileName = h.name(); foreach(const QVariant &var_prio, files_priority) {
QFile pieces_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".priorities"); int priority = var_prio.toInt();
has_filtered_files = false;
qDebug("Loading pieces priorities");
// Read saved file
if(!pieces_file.open(QIODevice::ReadOnly | QIODevice::Text)){
qDebug("Could not find pieces file");
for(unsigned int i=0; i<nbFiles; ++i)
prioritiesTab[i] = NORMAL;
return prioritiesTab;
}
QByteArray pieces_text = pieces_file.readAll();
pieces_file.close();
QList<QByteArray> pieces_priority_list = pieces_text.split('\n');
if((unsigned int)pieces_priority_list.size() != nbFiles+1){
std::cerr << "Error: Corrupted pieces file\n";
for(unsigned int i=0; i<nbFiles; ++i)
prioritiesTab[i] = NORMAL;
return prioritiesTab;
}
for(unsigned int i=0; i<nbFiles; ++i){
int priority = pieces_priority_list.at(i).toInt();
if( priority < 0 || priority > 7){ if( priority < 0 || priority > 7){
// Normal priority as default // Normal priority as default
priority = 1; priority = 1;
} }
if(!priority){ fp.push_back(priority);
has_filtered_files = true;
}
prioritiesTab[i] = priority;
} }
return prioritiesTab;
return fp;
} }
bool properties::allFiltered() const { bool properties::allFiltered() const {
@ -494,7 +468,7 @@ void properties::askWebSeed(){
} }
urlSeeds << url_seed; urlSeeds << url_seed;
h.add_url_seed(url_seed); h.add_url_seed(url_seed);
saveWebSeeds(); TorrentPersistentData::saveUrlSeeds(h);
// Refresh the seeds list // Refresh the seeds list
loadWebSeeds(); loadWebSeeds();
} }
@ -536,7 +510,7 @@ void properties::deleteSelectedUrlSeeds(){
} }
if(change){ if(change){
// Save them to disk // Save them to disk
saveWebSeeds(); TorrentPersistentData::saveUrlSeeds(h);
// Refresh list // Refresh list
loadWebSeeds(); loadWebSeeds();
} }
@ -672,19 +646,16 @@ void properties::setAllPiecesState(unsigned short priority){
} }
} }
void properties::on_incrementalDownload_stateChanged(int){ void properties::on_incrementalDownload_stateChanged(int state){
qDebug("Incremental download toggled"); qDebug("Incremental download toggled");
if(incrementalDownload->isChecked()){ if(state == Qt::Checked){
if(!QFile::exists(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".incremental"))) { if(!TorrentPersistentData::isSequentialDownload(hash)) {
// Create .incremental file
QFile incremental_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".incremental"));
incremental_file.open(QIODevice::WriteOnly | QIODevice::Text);
incremental_file.close();
h.set_sequential_download(true); h.set_sequential_download(true);
TorrentPersistentData::saveSequentialStatus(h);
} }
}else{ }else{
QFile::remove(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".incremental");
h.set_sequential_download(false); h.set_sequential_download(false);
TorrentPersistentData::saveSequentialStatus(h);
} }
} }
@ -706,12 +677,10 @@ void properties::on_changeSavePathButton_clicked() {
} }
} }
// Save savepath // Save savepath
QFile savepath_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".savepath")); TorrentPersistentData::saveSavePath(hash, savePath.path());
savepath_file.open(QIODevice::WriteOnly | QIODevice::Text);
savepath_file.write(savePath.path().toLocal8Bit());
savepath_file.close();
// Actually move storage // Actually move storage
h.move_storage(savePath.path()); if(!BTSession->useTemporaryFolder() || h.is_seed())
h.move_storage(savePath.path());
// Update save_path in dialog // Update save_path in dialog
save_path->setText(savePath.path()); save_path->setText(savePath.path());
} }
@ -723,13 +692,10 @@ void properties::on_okButton_clicked(){
} }
void properties::loadWebSeedsFromFile(){ void properties::loadWebSeedsFromFile(){
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');
urlSeeds.clear(); urlSeeds.clear();
foreach(const QByteArray &url_seed, url_seeds){ QVariantList url_seeds = TorrentPersistentData::getUrlSeeds(hash);
foreach(const QVariant &var_url_seed, url_seeds){
QString url_seed = var_url_seed.toString();
if(!url_seed.isEmpty()) if(!url_seed.isEmpty())
urlSeeds << url_seed; urlSeeds << url_seed;
} }
@ -743,19 +709,6 @@ void properties::loadWebSeedsFromFile(){
} }
} }
void properties::saveWebSeeds(){
QFile urlseeds_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".urlseeds"));
if(!urlseeds_file.open(QIODevice::WriteOnly | QIODevice::Text)){
std::cerr << "Error: Could not save url seeds\n";
return;
}
foreach(const QString &url_seed, urlSeeds){
urlseeds_file.write((url_seed+"\n").toLocal8Bit());
}
urlseeds_file.close();
qDebug("url seeds were saved");
}
bool properties::savePiecesPriorities() { bool properties::savePiecesPriorities() {
if(!changedFilteredfiles) return true; if(!changedFilteredfiles) return true;
if(allFiltered()) { if(allFiltered()) {
@ -763,30 +716,15 @@ bool properties::savePiecesPriorities() {
return false; return false;
} }
qDebug("Saving pieces priorities"); qDebug("Saving pieces priorities");
bool hasFilteredFiles = false;
QString fileName = h.name();
QFile pieces_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".priorities"));
// First, remove old file
pieces_file.remove();
int *priorities = new int[h.get_torrent_info().num_files()]; int *priorities = new int[h.get_torrent_info().num_files()];
getPriorities(PropListModel->invisibleRootItem(), priorities); getPriorities(PropListModel->invisibleRootItem(), priorities);
// Ok, we have priorities, save them
if(!pieces_file.open(QIODevice::WriteOnly | QIODevice::Text)){
std::cerr << "Error: Could not save pieces priorities\n";
return true;
}
unsigned int nbFiles = h.get_torrent_info().num_files(); unsigned int nbFiles = h.get_torrent_info().num_files();
for(unsigned int i=0; i<nbFiles; ++i) { for(unsigned int i=0; i<nbFiles; ++i) {
if(!priorities[i]) { h.file_priority(i, priorities[i]);
hasFilteredFiles = true;
}
pieces_file.write(misc::toQByteArray(priorities[i])+misc::toQByteArray("\n"));
} }
pieces_file.close();
delete[] priorities; delete[] priorities;
BTSession->loadFilesPriorities(h); TorrentPersistentData::saveFilesPriority(h);
// Emit a signal so that the GUI updates the size // Emit a signal so that the GUI updates the size
emit filteredFilesChanged(hash); emit filteredFilesChanged(hash);
has_filtered_files = hasFilteredFiles;
return true; return true;
} }

4
src/properties_imp.h

@ -55,7 +55,6 @@ class properties : public QDialog, private Ui::properties{
PropListDelegate *PropDelegate; PropListDelegate *PropDelegate;
QStandardItemModel *PropListModel; QStandardItemModel *PropListModel;
QTimer *updateInfosTimer; QTimer *updateInfosTimer;
bool has_filtered_files;
QStringList urlSeeds; QStringList urlSeeds;
RealProgressBar *progressBar; RealProgressBar *progressBar;
RealProgressBarThread *progressBarUpdater; RealProgressBarThread *progressBarUpdater;
@ -79,7 +78,6 @@ class properties : public QDialog, private Ui::properties{
void maximumSelection(); void maximumSelection();
void loadWebSeeds(); void loadWebSeeds();
void askWebSeed(); void askWebSeed();
void saveWebSeeds();
void loadWebSeedsFromFile(); void loadWebSeedsFromFile();
void deleteSelectedUrlSeeds(); void deleteSelectedUrlSeeds();
void addFilesToTree(const torrent_file *root, QStandardItem *parent); void addFilesToTree(const torrent_file *root, QStandardItem *parent);
@ -103,7 +101,7 @@ class properties : public QDialog, private Ui::properties{
~properties(); ~properties();
bool allFiltered() const; bool allFiltered() const;
bool savePiecesPriorities(); bool savePiecesPriorities();
int* loadPiecesPriorities(); std::vector<int> loadFilesPriorities();
protected: protected:
QPoint screenCenter() const; QPoint screenCenter() const;

15
src/qtorrenthandle.cpp

@ -241,6 +241,11 @@ torrent_status::state_t QTorrentHandle::state() const {
return h.status().state; return h.status().state;
} }
std::vector<int> QTorrentHandle::file_priorities() const {
Q_ASSERT(h.is_valid());
return h.file_priorities();
}
QString QTorrentHandle::creator() const { QString QTorrentHandle::creator() const {
Q_ASSERT(h.is_valid()); Q_ASSERT(h.is_valid());
return misc::toQString(h.get_torrent_info().creator()); return misc::toQString(h.get_torrent_info().creator());
@ -325,6 +330,11 @@ int QTorrentHandle::active_time() const {
return h.status().active_time; return h.status().active_time;
} }
bool QTorrentHandle::is_sequential_download() const {
Q_ASSERT(h.is_valid());
return h.is_sequential_download();
}
// //
// Setters // Setters
// //
@ -428,6 +438,11 @@ void QTorrentHandle::move_storage(QString new_path) const {
h.move_storage(new_path.toLocal8Bit().data()); h.move_storage(new_path.toLocal8Bit().data());
} }
void QTorrentHandle::file_priority(int index, int priority) const {
Q_ASSERT(h.is_valid());
h.file_priority(index, priority);
}
// //
// Operators // Operators
// //

3
src/qtorrenthandle.h

@ -108,6 +108,8 @@ class QTorrentHandle {
bool is_seed() const; bool is_seed() const;
bool is_auto_managed() const; bool is_auto_managed() const;
int active_time() const; int active_time() const;
std::vector<int> file_priorities() const;
bool is_sequential_download() const;
// //
// Setters // Setters
@ -122,6 +124,7 @@ class QTorrentHandle {
void set_max_uploads(int val); void set_max_uploads(int val);
void set_max_connections(int val); void set_max_connections(int val);
void prioritize_files(std::vector<int> v); void prioritize_files(std::vector<int> v);
void file_priority(int index, int priority) const;
void set_ratio(float ratio) const; void set_ratio(float ratio) const;
void replace_trackers(std::vector<announce_entry> const&) const; void replace_trackers(std::vector<announce_entry> const&) const;
void force_reannounce(); void force_reannounce();

28
src/torrentAddition.h

@ -48,6 +48,7 @@
#include "PropListDelegate.h" #include "PropListDelegate.h"
#include "ui_addTorrentDialog.h" #include "ui_addTorrentDialog.h"
#include "arborescence.h" #include "arborescence.h"
#include "torrentPersistentData.h"
using namespace libtorrent; using namespace libtorrent;
@ -371,22 +372,14 @@ class torrentAdditionDialog : public QDialog, private Ui_addTorrentDialog{
void savePiecesPriorities(){ void savePiecesPriorities(){
qDebug("Saving pieces priorities"); qDebug("Saving pieces priorities");
QFile pieces_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".priorities"));
// First, remove old file
pieces_file.remove();
int *priorities = new int[nbFiles]; int *priorities = new int[nbFiles];
getPriorities(PropListModel->invisibleRootItem(), priorities); getPriorities(PropListModel->invisibleRootItem(), priorities);
// Ok, we have priorities, save them std::vector<int> vect_prio;
if(!pieces_file.open(QIODevice::WriteOnly | QIODevice::Text)){
std::cerr << "Error: Could not save pieces priorities\n";
return;
}
for(unsigned int i=0; i<nbFiles; ++i) { for(unsigned int i=0; i<nbFiles; ++i) {
qDebug("%d ", priorities[i]); vect_prio.push_back(priorities[i]);
pieces_file.write(misc::toQByteArray(priorities[i])+misc::toQByteArray("\n"));
} }
pieces_file.close();
delete[] priorities; delete[] priorities;
TorrentTempData::setFilesPriority(hash, vect_prio);
} }
void on_OkButton_clicked(){ void on_OkButton_clicked(){
@ -403,21 +396,12 @@ class torrentAdditionDialog : public QDialog, private Ui_addTorrentDialog{
} }
} }
// Save savepath // Save savepath
QFile savepath_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".savepath")); TorrentTempData::setSavePath(hash, savePath.path());
savepath_file.open(QIODevice::WriteOnly | QIODevice::Text);
savepath_file.write(savePath.path().toLocal8Bit());
savepath_file.close();
// Save last dir to remember it // Save last dir to remember it
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
settings.setValue(QString::fromUtf8("LastDirTorrentAdd"), savePathTxt->text()); settings.setValue(QString::fromUtf8("LastDirTorrentAdd"), savePathTxt->text());
// Create .incremental file if necessary // Create .incremental file if necessary
if(checkIncrementalDL->isChecked()){ TorrentTempData::setSequential(hash, checkIncrementalDL->isChecked());
QFile incremental_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".incremental"));
incremental_file.open(QIODevice::WriteOnly | QIODevice::Text);
incremental_file.close();
}else{
QFile::remove(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".incremental"));
}
// Check if there is at least one selected file // Check if there is at least one selected file
if(allFiltered()){ if(allFiltered()){
QMessageBox::warning(0, tr("Invalid file selection"), tr("You must select at least one file in the torrent")); QMessageBox::warning(0, tr("Invalid file selection"), tr("You must select at least one file in the torrent"));

339
src/torrentPersistentData.h

@ -0,0 +1,339 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#ifndef TORRENTPERSISTENTDATA_H
#define TORRENTPERSISTENTDATA_H
#include <QSettings>
#include <QHash>
#include <QVariant>
#include <libtorrent/magnet_uri.hpp>
#include "qtorrenthandle.h"
#include "misc.h"
class TorrentTempData {
public:
static bool hasTempData(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
return all_data.contains(hash);
}
static void deleteTempData(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
if(all_data.contains(hash)) {
all_data.remove(hash);
settings.setValue("torrents-tmp", all_data);
}
}
static void setFilesPriority(QString hash, std::vector<int> pp) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
std::vector<int>::iterator pp_it = pp.begin();
QVariantList pieces_priority;
while(pp_it != pp.end()) {
pieces_priority << *pp_it;
pp_it++;
}
data["files_priority"] = pieces_priority;
all_data[hash] = data;
settings.setValue("torrents-tmp", all_data);
}
static void setSavePath(QString hash, QString save_path) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
data["save_path"] = save_path;
all_data[hash] = data;
settings.setValue("torrents-tmp", all_data);
}
static void setSequential(QString hash, bool sequential) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
data["sequential"] = sequential;
all_data[hash] = data;
settings.setValue("torrents-tmp", all_data);
}
static bool isSequential(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
if(data.contains("sequential"))
return data["sequential"].toBool();
return false;
}
static QString getSavePath(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
if(data.contains("save_path"))
return data["save_path"].toString();
qDebug("Warning Temp::getSavePath returns null string!");
return QString::null;
}
static QVariantList getFilesPriority(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
if(data.contains("files_priority"))
return data["files_priority"].toList();
return QVariantList();
}
};
class TorrentPersistentData {
public:
static bool isKnownTorrent(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
return all_data.contains(hash);
}
static QStringList knownTorrents() {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
return all_data.keys();
}
static void deletePersistentData(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
if(all_data.contains(hash)) {
all_data.remove(hash);
settings.setValue("torrents", all_data);
}
}
static void saveTorrentPersistentData(QTorrentHandle h, bool is_magnet = false) {
// First, remove temp data
TorrentTempData::deleteTempData(h.hash());
Q_ASSERT(!TorrentTempData::hasTempData(h.hash()));
// Save persistent data
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data;
data["hash"] = h.hash();
data["is_magnet"] = is_magnet;
if(is_magnet) {
data["magnet_uri"] = misc::toQString(make_magnet_uri(h.get_torrent_handle()));
}
data["seed"] = h.is_seed();
data["priority"] = h.queue_position();
QVariantList files_priority;
std::vector<int> fp = h.file_priorities();
std::vector<int>::iterator fp_it = fp.begin();
while(fp_it != fp.end()) {
files_priority << *fp_it;
fp_it++;
}
data["files_priority"] = files_priority;
data["save_path"] = h.save_path();
QHash<QString, QVariant> trackers;
std::vector<announce_entry> tr = h.trackers();
std::vector<announce_entry>::iterator tr_it = tr.begin();
while(tr_it != tr.end()) {
trackers[misc::toQString((*tr_it).url)] = (*tr_it).tier;
tr_it++;
}
data["trackers"] = trackers;
QVariantList url_seeds;
foreach(QString url_seed, h.url_seeds()) {
url_seeds << url_seed;
}
data["url_seeds"] = url_seeds;
data["sequential"] = h.is_sequential_download();
// Save data
all_data[h.hash()] = data;
settings.setValue("torrents", all_data);
}
static void saveTrackers(QTorrentHandle h) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[h.hash()].toHash();
QVariantList trackers;
std::vector<announce_entry> tr = h.trackers();
std::vector<announce_entry>::iterator tr_it = tr.begin();
while(tr_it != tr.end()) {
trackers << misc::toQString((*tr_it).url);
tr_it++;
}
data["trackers"] = trackers;
// Save data
all_data[h.hash()] = data;
settings.setValue("torrents", all_data);
}
// Setters
static void saveFilesPriority(QTorrentHandle h) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[h.hash()].toHash();
std::vector<int> fp = h.file_priorities();
std::vector<int>::iterator fp_it = fp.begin();
QVariantList files_priority;
while(fp_it != fp.end()) {
files_priority << *fp_it;
fp_it++;
}
data["files_priority"] = files_priority;
all_data[h.hash()] = data;
settings.setValue("torrents", all_data);
}
static void saveSavePath(QString hash, QString save_path) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
data["save_path"] = save_path;
all_data[hash] = data;
settings.setValue("torrents", all_data);
}
static void saveUrlSeeds(QTorrentHandle h) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[h.hash()].toHash();
QVariantList url_seeds;
foreach(QString url_seed, h.url_seeds()) {
url_seeds << url_seed;
}
data["url_seeds"] = url_seeds;
all_data[h.hash()] = data;
settings.setValue("torrents", all_data);
}
static void savePriority(QTorrentHandle h) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[h.hash()].toHash();
data["priority"] = h.queue_position();
all_data[h.hash()] = data;
settings.setValue("torrents", all_data);
}
static void saveSeedStatus(QTorrentHandle h) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[h.hash()].toHash();
data["seed"] = h.is_seed();
all_data[h.hash()] = data;
settings.setValue("torrents", all_data);
}
static void saveSequentialStatus(QTorrentHandle h) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[h.hash()].toHash();
data["sequential"] = h.is_sequential_download();
all_data[h.hash()] = data;
settings.setValue("torrents", all_data);
}
// Getters
static QHash<QString, QVariant> getTrackers(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
return data["trackers"].toHash();
}
static QVariantList getFilesPriority(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
return data["files_priority"].toList();
}
static QString getSavePath(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
return data["save_path"].toString();
}
static int getPriority(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
return data["priority"].toInt();
}
static QVariantList getUrlSeeds(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
return data["url_seeds"].toList();
}
static bool isSeed(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
return data["seed"].toBool();
}
static bool isMagnet(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
return data["is_magnet"].toBool();
}
static QString getMagnetUri(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
Q_ASSERT(data["is_magnet"].toBool());
return data["magnet_uri"].toString();
}
static bool isSequentialDownload(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
return data["sequential"].toBool();
}
};
#endif // TORRENTPERSISTENTDATA_H
Loading…
Cancel
Save