- Added Magnet URI support (might be still buggy)

* Known problem: Always added in paused state for some obscure reason)
This commit is contained in:
Christophe Dumez 2009-08-17 05:14:03 +00:00
parent 2742a54d6e
commit e619b6977a
13 changed files with 848 additions and 650 deletions

View file

@ -1,4 +1,5 @@
* Unknown - Christophe Dumez <chris@qbittorrent.org> - v1.5.0 * Unknown - Christophe Dumez <chris@qbittorrent.org> - v1.5.0
- FEATURE: Added Magnet URI support
- BUGFIX: torrent resume code rewrited - 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

View file

@ -64,6 +64,8 @@ FinishedTorrents::FinishedTorrents(QObject *parent, bittorrent *BTSession) : par
if(!loadColWidthFinishedList()){ if(!loadColWidthFinishedList()){
finishedList->header()->resizeSection(0, 200); finishedList->header()->resizeSection(0, 200);
} }
// Connect BTSession signals
connect(BTSession, SIGNAL(metadataReceived(QTorrentHandle&)), this, SLOT(updateMetadata(QTorrentHandle&)));
// Make download list header clickable for sorting // Make download list header clickable for sorting
finishedList->header()->setClickable(true); finishedList->header()->setClickable(true);
finishedList->header()->setSortIndicatorShown(true); finishedList->header()->setSortIndicatorShown(true);
@ -266,6 +268,16 @@ void FinishedTorrents::on_actionSet_upload_limit_triggered(){
new BandwidthAllocationDialog(this, true, BTSession, hashes); new BandwidthAllocationDialog(this, true, BTSession, hashes);
} }
void FinishedTorrents::updateMetadata(QTorrentHandle &h) {
QString hash = h.hash();
int row = getRowFromHash(hash);
if(row != -1) {
qDebug("Updating torrent metadata in download list");
finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(h.name()));
finishedListModel->setData(finishedListModel->index(row, F_SIZE), QVariant((qlonglong)h.actual_size()));
}
}
void FinishedTorrents::updateTorrent(QTorrentHandle h) { void FinishedTorrents::updateTorrent(QTorrentHandle h) {
QString hash = h.hash(); QString hash = h.hash();
int row = getRowFromHash(hash); int row = getRowFromHash(hash);

View file

@ -93,6 +93,7 @@ class FinishedTorrents : public QWidget, public Ui::seeding {
void deleteTorrent(QString hash); void deleteTorrent(QString hash);
void showPropertiesFromHash(QString hash); void showPropertiesFromHash(QString hash);
void loadLastSortedColumn(); void loadLastSortedColumn();
void updateMetadata(QTorrentHandle &h);
signals: signals:
void torrentMovedFromFinishedList(QString); void torrentMovedFromFinishedList(QString);

View file

@ -763,6 +763,11 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
BTSession->downloadFromUrl(file); BTSession->downloadFromUrl(file);
continue; continue;
} }
if(file.startsWith("magnet:", Qt::CaseInsensitive)) {
// FIXME: Possibly skipped torrent addition dialog
BTSession->addMagnetUri(file);
continue;
}
if(useTorrentAdditionDialog) { if(useTorrentAdditionDialog) {
torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession); torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession);
dialog->showLoad(file); dialog->showLoad(file);
@ -921,6 +926,10 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
if(param.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) { if(param.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) {
BTSession->downloadFromUrl(param); BTSession->downloadFromUrl(param);
}else{ }else{
if(param.startsWith("magnet:", Qt::CaseInsensitive)) {
// FIXME: Possibily skipped torrent addition dialog
BTSession->addMagnetUri(param);
} else {
if(useTorrentAdditionDialog) { if(useTorrentAdditionDialog) {
torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession); torrentAdditionDialog *dialog = new torrentAdditionDialog(this, BTSession);
dialog->showLoad(param); dialog->showLoad(param);
@ -930,6 +939,7 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
} }
} }
} }
}
void GUI::addTorrent(QString path) { void GUI::addTorrent(QString path) {
BTSession->addTorrent(path); BTSession->addTorrent(path);
@ -1491,8 +1501,14 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
* * * *
*****************************************************/ *****************************************************/
void GUI::downloadFromURLList(const QStringList& urls) { void GUI::downloadFromURLList(const QStringList& url_list) {
BTSession->downloadFromURLList(urls); foreach(const QString url, url_list) {
if(url.startsWith("magnet:", Qt::CaseInsensitive)) {
BTSession->addMagnetUri(url);
} else {
BTSession->downloadFromUrl(url);
}
}
} }
/***************************************************** /*****************************************************

View file

@ -37,7 +37,7 @@
#include "misc.h" #include "misc.h"
class torrent_file { class torrent_file {
private: private:
torrent_file *parent; torrent_file *parent;
bool is_dir; bool is_dir;
QString rel_path; QString rel_path;
@ -47,7 +47,7 @@ class torrent_file {
int priority; int priority;
int index; // Index in torrent_info int index; // Index in torrent_info
public: public:
torrent_file(torrent_file *parent, QString path, bool dir, size_type size=0, int index=-1, float progress=0., int priority=1): parent(parent), is_dir(dir), size(size), progress(progress), priority(priority), index(index){ torrent_file(torrent_file *parent, QString path, bool dir, size_type size=0, int index=-1, float progress=0., int priority=1): parent(parent), is_dir(dir), size(size), progress(progress), priority(priority), index(index){
qDebug("created a file with index %d", index); qDebug("created a file with index %d", index);
rel_path = QDir::cleanPath(path); rel_path = QDir::cleanPath(path);
@ -175,10 +175,10 @@ class torrent_file {
}; };
class arborescence { class arborescence {
private: private:
torrent_file *root; torrent_file *root;
public: public:
arborescence(boost::intrusive_ptr<torrent_info> t) { arborescence(boost::intrusive_ptr<torrent_info> t) {
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) {
@ -237,7 +237,7 @@ class arborescence {
return success; return success;
} }
protected: protected:
void addFile(QString path, size_type file_size, int index, float progress=0., int priority=1) { void addFile(QString path, size_type file_size, int index, float progress=0., int priority=1) {
Q_ASSERT(root->isDir()); Q_ASSERT(root->isDir());
path = QDir::cleanPath(path); path = QDir::cleanPath(path);

View file

@ -360,6 +360,123 @@ void bittorrent::loadWebSeeds(QString hash) {
} }
} }
QTorrentHandle bittorrent::addMagnetUri(QString magnet_uri, bool resumed) {
QTorrentHandle h;
QString hash = misc::magnetUriToHash(magnet_uri);
if(hash.isEmpty()) {
addConsoleMessage(tr("'%1' is not a valid magnet URI.").arg(magnet_uri));
return h;
}
if(resumed) {
qDebug("Resuming magnet URI: %s", hash.toUtf8().data());
} else {
qDebug("Adding new magnet URI");
}
bool fastResume=false;
Q_ASSERT(magnet_uri.startsWith("magnet:"));
QDir torrentBackup(misc::qBittorrentPath() + "BT_backup");
// Checking if BT_backup Dir exists
// create it if it is not
if(! torrentBackup.exists()) {
if(! torrentBackup.mkpath(torrentBackup.path())) {
std::cerr << "Couldn't create the directory: '" << torrentBackup.path().toLocal8Bit().data() << "'\n";
exit(1);
}
}
// Check if torrent is already in download list
if(s->find_torrent(sha1_hash(hash.toUtf8().data())).is_valid()) {
qDebug("/!\\ Torrent is already in download list");
// Update info Bar
addConsoleMessage(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(magnet_uri));
return h;
}
add_torrent_params p;
//Getting fast resume data if existing
std::vector<char> buf;
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);
qDebug("addMagnetURI: 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();
}
// Preallocate all?
if(preAllocateAll)
p.storage_mode = storage_mode_allocate;
else
p.storage_mode = storage_mode_sparse;
// Start in pause
//p.paused = true;
p.duplicate_is_error = false; // Already checked
p.auto_managed = false; // Because it is added in paused state
// Adding torrent to bittorrent session
try {
h = QTorrentHandle(add_magnet_uri(*s, magnet_uri.toStdString(), 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");
return h;
}
Q_ASSERT(h.hash() == hash);
// Connections limit per torrent
h.set_max_connections(maxConnecsPerTorrent);
// Uploads limit per torrent
h.set_max_uploads(maxUploadsPerTorrent);
// Load filtered files
if(resumed) {
// Load custom url seeds
loadWebSeeds(hash);
// Load speed limit from hard drive
loadTorrentSpeedLimits(hash);
// Load trackers
loadTrackerFile(hash);
// XXX: only when resuming because torrentAddition dialog is not supported yet
loadFilesPriorities(h);
} else {
// Sequential download
if(TorrentTempData::hasTempData(hash)) {
qDebug("addMagnetUri: Setting download as sequential (from tmp data)");
h.set_sequential_download(TorrentTempData::isSequential(hash));
}
// Save persistent data for new torrent
Q_ASSERT(h.is_valid());
qDebug("addMagnetUri: hash: %s", h.hash().toUtf8().data());
TorrentPersistentData::saveTorrentPersistentData(h, true);
qDebug("Persistent data saved");
// Save save_path
if(!defaultTempPath.isEmpty()) {
qDebug("addMagnetUri: Saving save_path in persistent data: %s", savePath.toUtf8().data());
TorrentPersistentData::saveSavePath(hash, savePath);
}
}
if(!addInPause && !fastResume) {
// Start torrent because it was added in paused state
h.resume();
}
// Send torrent addition signal
if(fastResume)
addConsoleMessage(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(magnet_uri));
else
addConsoleMessage(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(magnet_uri));
emit addedTorrent(h);
return h;
}
// 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 resumed) { QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString from_url, bool resumed) {
QTorrentHandle h; QTorrentHandle h;
@ -406,13 +523,7 @@ QTorrentHandle bittorrent::addTorrent(QString path, bool fromScanDir, QString fr
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());
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());
}
}
// 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");
@ -726,7 +837,7 @@ void bittorrent::loadTorrentSpeedLimits(QString hash) {
// Read pieces priorities from hard disk // 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 files priority");
if(!h.is_valid()) { if(!h.is_valid()) {
qDebug("/!\\ Error: Invalid handle"); qDebug("/!\\ Error: Invalid handle");
return; return;
@ -1142,6 +1253,10 @@ void bittorrent::readAlerts() {
bencode(std::ostream_iterator<char>(out), *p->resume_data); bencode(std::ostream_iterator<char>(out), *p->resume_data);
} }
} }
else if (metadata_received_alert* p = dynamic_cast<metadata_received_alert*>(a.get())) {
QTorrentHandle h(p->handle);
emit metadataReceived(h);
}
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);
h.auto_managed(false); h.auto_managed(false);
@ -1300,13 +1415,6 @@ void bittorrent::processDownloadedFile(QString url, QString file_path) {
} }
} }
void bittorrent::downloadFromURLList(const QStringList& url_list) {
qDebug("DownloadFromUrlList");
foreach(const QString url, url_list) {
downloadFromUrl(url);
}
}
// Return current download rate for the BT // Return current download rate for the BT
// session. Payload means that it only take into // session. Payload means that it only take into
// account "useful" part of the rate // account "useful" part of the rate
@ -1352,7 +1460,7 @@ void bittorrent::startUpTorrents() {
QStringList fileNames; QStringList fileNames;
QStringList known_torrents = TorrentPersistentData::knownTorrents(); QStringList known_torrents = TorrentPersistentData::knownTorrents();
if(isQueueingEnabled()) { if(isQueueingEnabled()) {
QList<QPair<int, QString> > filePaths; QList<QPair<int, QString> > hashes;
foreach(const QString &hash, known_torrents) { foreach(const QString &hash, known_torrents) {
QString filePath; QString filePath;
if(TorrentPersistentData::isMagnet(hash)) { if(TorrentPersistentData::isMagnet(hash)) {
@ -1361,21 +1469,27 @@ void bittorrent::startUpTorrents() {
filePath = torrentBackup.path()+QDir::separator()+hash+".torrent"; filePath = torrentBackup.path()+QDir::separator()+hash+".torrent";
} }
int prio = TorrentPersistentData::getPriority(hash); int prio = TorrentPersistentData::getPriority(hash);
misc::insertSort2<QString>(filePaths, qMakePair(prio, filePath)); misc::insertSort2<QString>(hashes, qMakePair(prio, hash));
} }
// Resume downloads // Resume downloads
QPair<int, QString> fileName; QPair<int, QString> couple;
foreach(fileName, filePaths) { foreach(couple, hashes) {
addTorrent(fileName.second, false, QString(), true); QString hash = couple.second;
qDebug("Starting up torrent %s", hash.toUtf8().data());
if(TorrentPersistentData::isMagnet(hash)) {
addMagnetUri(TorrentPersistentData::getMagnetUri(hash), true);
} else {
addTorrent(torrentBackup.path()+QDir::separator()+hash+".torrent", false, QString(), true);
}
} }
} else { } else {
QStringList filePaths;
foreach(const QString &fileName, fileNames) {
filePaths.append(torrentBackup.path()+QDir::separator()+fileName);
}
// Resume downloads // Resume downloads
foreach(const QString &fileName, filePaths) { foreach(const QString &hash, known_torrents) {
addTorrent(fileName, false, QString(), true); qDebug("Starting up torrent %s", hash.toUtf8().data());
if(TorrentPersistentData::isMagnet(hash))
addMagnetUri(TorrentPersistentData::getMagnetUri(hash), true);
else
addTorrent(torrentBackup.path()+QDir::separator()+hash+".torrent", false, QString(), true);
} }
} }
qDebug("Unfinished torrents resumed"); qDebug("Unfinished torrents resumed");

View file

@ -111,10 +111,10 @@ class bittorrent : public QObject {
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);
QTorrentHandle addMagnetUri(QString magnet_uri, bool resumed=false);
void loadSessionState(); void loadSessionState();
void saveSessionState(); void saveSessionState();
void downloadFromUrl(QString url); void downloadFromUrl(QString url);
void downloadFromURLList(const QStringList& url_list);
void deleteTorrent(QString hash, bool permanent = false); void deleteTorrent(QString hash, bool permanent = false);
void startUpTorrents(); void startUpTorrents();
/* Needed by Web UI */ /* Needed by Web UI */
@ -185,6 +185,7 @@ class bittorrent : public QObject {
void updateFileSize(QString hash); void updateFileSize(QString hash);
void downloadFromUrlFailure(QString url, QString reason); void downloadFromUrlFailure(QString url, QString reason);
void torrentFinishedChecking(QTorrentHandle& h); void torrentFinishedChecking(QTorrentHandle& h);
void metadataReceived(QTorrentHandle &h);
}; };
#endif #endif

View file

@ -53,8 +53,8 @@ DownloadingTorrents::DownloadingTorrents(QObject *parent, bittorrent *BTSession)
actionSet_download_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))); actionSet_download_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png")));
actionDelete_Permanently->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png"))); actionDelete_Permanently->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png")));
actionTorrent_Properties->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/properties.png"))); actionTorrent_Properties->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/properties.png")));
// tabBottom->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/oxygen/log.png"))); // tabBottom->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/oxygen/log.png")));
// tabBottom->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/oxygen/filter.png"))); // tabBottom->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/oxygen/filter.png")));
// Set Download list model // Set Download list model
DLListModel = new QStandardItemModel(0,10); DLListModel = new QStandardItemModel(0,10);
@ -79,6 +79,7 @@ DownloadingTorrents::DownloadingTorrents(QObject *parent, bittorrent *BTSession)
loadHiddenColumns(); loadHiddenColumns();
connect(BTSession, SIGNAL(torrentFinishedChecking(QTorrentHandle&)), this, SLOT(sortProgressColumn(QTorrentHandle&))); connect(BTSession, SIGNAL(torrentFinishedChecking(QTorrentHandle&)), this, SLOT(sortProgressColumn(QTorrentHandle&)));
connect(BTSession, SIGNAL(metadataReceived(QTorrentHandle&)), this, SLOT(updateMetadata(QTorrentHandle&)));
// Load last columns width for download list // Load last columns width for download list
if(!loadColWidthDLList()) { if(!loadColWidthDLList()) {
@ -173,10 +174,12 @@ void DownloadingTorrents::showProperties(const QModelIndex &index) {
void DownloadingTorrents::showPropertiesFromHash(QString hash) { void DownloadingTorrents::showPropertiesFromHash(QString hash) {
QTorrentHandle h = BTSession->getTorrentHandle(hash); QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(h.is_valid() && h.has_metadata()) {
properties *prop = new properties(this, BTSession, h); properties *prop = new properties(this, BTSession, h);
connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSizeAndProgress(QString))); connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSizeAndProgress(QString)));
connect(prop, SIGNAL(trackersChanged(QString)), BTSession, SLOT(saveTrackerFile(QString))); connect(prop, SIGNAL(trackersChanged(QString)), BTSession, SLOT(saveTrackerFile(QString)));
prop->show(); prop->show();
}
} }
// Remove a torrent from the download list but NOT from the BT Session // Remove a torrent from the download list but NOT from the BT Session
@ -243,13 +246,19 @@ void DownloadingTorrents::displayDLListMenu(const QPoint&) {
// Enable/disable pause/start action given the DL state // Enable/disable pause/start action given the DL state
QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes();
bool has_pause = false, has_start = false, has_preview = false; bool has_pause = false, has_start = false, has_preview = false;
bool show_properties_entry = false;
QTorrentHandle h;
qDebug("Displaying menu");
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
if(index.column() == NAME) { if(index.column() == NAME) {
// Get the file name // Get the file name
QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString(); QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString();
// Get handle and pause the torrent // Get handle and pause the torrent
QTorrentHandle h = BTSession->getTorrentHandle(hash); h = BTSession->getTorrentHandle(hash);
if(!h.is_valid()) continue; if(!h.is_valid()) continue;
if(h.has_metadata()) {
show_properties_entry = true;
}
if(h.is_paused()) { if(h.is_paused()) {
if(!has_start) { if(!has_start) {
myDLLlistMenu.addAction(actionStart); myDLLlistMenu.addAction(actionStart);
@ -261,7 +270,7 @@ void DownloadingTorrents::displayDLListMenu(const QPoint&) {
has_pause = true; has_pause = true;
} }
} }
if(BTSession->isFilePreviewPossible(hash) && !has_preview) { if(h.has_metadata() && BTSession->isFilePreviewPossible(hash) && !has_preview) {
myDLLlistMenu.addAction(actionPreview_file); myDLLlistMenu.addAction(actionPreview_file);
has_preview = true; has_preview = true;
} }
@ -278,6 +287,7 @@ void DownloadingTorrents::displayDLListMenu(const QPoint&) {
myDLLlistMenu.addAction(actionForce_recheck); myDLLlistMenu.addAction(actionForce_recheck);
myDLLlistMenu.addSeparator(); myDLLlistMenu.addSeparator();
myDLLlistMenu.addAction(actionOpen_destination_folder); myDLLlistMenu.addAction(actionOpen_destination_folder);
if(show_properties_entry)
myDLLlistMenu.addAction(actionTorrent_Properties); myDLLlistMenu.addAction(actionTorrent_Properties);
if(BTSession->isQueueingEnabled()) { if(BTSession->isQueueingEnabled()) {
myDLLlistMenu.addSeparator(); myDLLlistMenu.addSeparator();
@ -462,7 +472,7 @@ QAction* DownloadingTorrents::getActionHoSCol(int index) {
break; break;
default : default :
return NULL; return NULL;
} }
} }
QStringList DownloadingTorrents::getSelectedTorrents(bool only_one) const{ QStringList DownloadingTorrents::getSelectedTorrents(bool only_one) const{
@ -479,6 +489,16 @@ QStringList DownloadingTorrents::getSelectedTorrents(bool only_one) const{
return res; return res;
} }
void DownloadingTorrents::updateMetadata(QTorrentHandle &h) {
QString hash = h.hash();
int row = getRowFromHash(hash);
if(row != -1) {
qDebug("Updating torrent metadata in download list");
DLListModel->setData(DLListModel->index(row, NAME), QVariant(h.name()));
DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size()));
}
}
// get information from torrent handles and // get information from torrent handles and
// update download list accordingly // update download list accordingly
bool DownloadingTorrents::updateTorrent(QTorrentHandle h) { bool DownloadingTorrents::updateTorrent(QTorrentHandle h) {

View file

@ -103,6 +103,7 @@ class DownloadingTorrents : public QWidget, public Ui::downloading{
void sortProgressColumn(QTorrentHandle& h); void sortProgressColumn(QTorrentHandle& h);
void loadLastSortedColumn(); void loadLastSortedColumn();
void addTorrent(QString hash); void addTorrent(QString hash);
void updateMetadata(QTorrentHandle &h);
}; };

View file

@ -49,7 +49,7 @@ using namespace libtorrent;
class misc : public QObject{ class misc : public QObject{
Q_OBJECT Q_OBJECT
public: public:
// Convert any type of variable to C++ String // Convert any type of variable to C++ String
// convert=true will convert -1 to 0 // convert=true will convert -1 to 0
template <class T> static std::string toString(const T& x, bool convert=false) { template <class T> static std::string toString(const T& x, bool convert=false) {
@ -238,6 +238,19 @@ class misc : public QObject{
return version; return version;
} }
static QString magnetUriToHash(QString magnet_uri) {
QString hash = "";
QRegExp reg("urn:btih:([A-Z2-7=]+)");
int pos = reg.indexIn(magnet_uri);
if(pos > -1) {
sha1_hash sha1;
sha1.assign(base32decode(reg.cap(1).toStdString()));
hash = misc::toQString(sha1);
}
qDebug("magnetUriToHash: hash: %s", hash.toUtf8().data());
return hash;
}
// Take a number of seconds and return an user-friendly // Take a number of seconds and return an user-friendly
// time duration like "1d 2h 10m". // time duration like "1d 2h 10m".
static QString userFriendlyDuration(qlonglong seconds) { static QString userFriendlyDuration(qlonglong seconds) {
@ -267,7 +280,7 @@ class misc : public QObject{
// Trick to get a portable sleep() function // Trick to get a portable sleep() function
class SleeperThread : public QThread{ class SleeperThread : public QThread{
public: public:
static void msleep(unsigned long msecs) static void msleep(unsigned long msecs)
{ {
QThread::msleep(msecs); QThread::msleep(msecs);

View file

@ -118,6 +118,7 @@ properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h
h.file_progress(fp); h.file_progress(fp);
std::vector<int> files_priority = loadFilesPriorities(); std::vector<int> files_priority = loadFilesPriorities();
// List files in torrent // List files in torrent
h.get_torrent_info();
arborescence *arb = new arborescence(h.get_torrent_info(), fp, files_priority); 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;
@ -137,7 +138,7 @@ properties::properties(QWidget *parent, bittorrent *BTSession, QTorrentHandle &h
progressBarVbox->addWidget(progressBar); progressBarVbox->addWidget(progressBar);
progressBarUpdater = new RealProgressBarThread(progressBar, h); progressBarUpdater = new RealProgressBarThread(progressBar, h);
progressBarUpdater->start(); progressBarUpdater->start();
// progressBarUpdater->refresh(); // progressBarUpdater->refresh();
connect(updateInfosTimer, SIGNAL(timeout()), progressBarUpdater, SLOT(refresh())); connect(updateInfosTimer, SIGNAL(timeout()), progressBarUpdater, SLOT(refresh()));
loadSettings(); loadSettings();
} }
@ -313,6 +314,11 @@ void properties::loadWebSeeds(){
std::vector<int> properties::loadFilesPriorities(){ std::vector<int> properties::loadFilesPriorities(){
std::vector<int> fp; std::vector<int> fp;
QVariantList files_priority = TorrentPersistentData::getFilesPriority(hash); QVariantList files_priority = TorrentPersistentData::getFilesPriority(hash);
if(files_priority.empty()) {
for(int i=0; i<h.num_files(); ++i) {
fp.push_back(1);
}
} else {
foreach(const QVariant &var_prio, files_priority) { foreach(const QVariant &var_prio, files_priority) {
int priority = var_prio.toInt(); int priority = var_prio.toInt();
if( priority < 0 || priority > 7){ if( priority < 0 || priority > 7){
@ -321,7 +327,7 @@ std::vector<int> properties::loadFilesPriorities(){
} }
fp.push_back(priority); fp.push_back(priority);
} }
}
return fp; return fp;
} }

View file

@ -35,6 +35,7 @@
#include <QByteArray> #include <QByteArray>
#include "misc.h" #include "misc.h"
#include "qtorrenthandle.h" #include "qtorrenthandle.h"
#include <libtorrent/magnet_uri.hpp>
QTorrentHandle::QTorrentHandle(torrent_handle h): h(h) {} QTorrentHandle::QTorrentHandle(torrent_handle h): h(h) {}
@ -54,7 +55,7 @@ torrent_info QTorrentHandle::get_torrent_info() const {
QString QTorrentHandle::hash() const { QString QTorrentHandle::hash() const {
Q_ASSERT(h.is_valid()); Q_ASSERT(h.is_valid());
return misc::toQString(h.get_torrent_info().info_hash()); return misc::toQString(h.info_hash());
} }
QString QTorrentHandle::name() const { QString QTorrentHandle::name() const {
@ -170,12 +171,14 @@ fs::path QTorrentHandle::save_path_boost() const {
QStringList QTorrentHandle::url_seeds() const { QStringList QTorrentHandle::url_seeds() const {
Q_ASSERT(h.is_valid()); Q_ASSERT(h.is_valid());
QStringList res; QStringList res;
try {
std::vector<std::string> existing_seeds = h.get_torrent_info().url_seeds(); std::vector<std::string> existing_seeds = h.get_torrent_info().url_seeds();
unsigned int nbSeeds = existing_seeds.size(); unsigned int nbSeeds = existing_seeds.size();
QString existing_seed; QString existing_seed;
for(unsigned int i=0; i<nbSeeds; ++i) { for(unsigned int i=0; i<nbSeeds; ++i) {
res << misc::toQString(existing_seeds[i]); res << misc::toQString(existing_seeds[i]);
} }
} catch(std::exception e) {}
return res; return res;
} }
@ -453,6 +456,6 @@ QTorrentHandle& QTorrentHandle::operator =(const torrent_handle& new_h) {
} }
bool QTorrentHandle::operator ==(const QTorrentHandle& new_h) const{ bool QTorrentHandle::operator ==(const QTorrentHandle& new_h) const{
QString hash = misc::toQString(h.get_torrent_info().info_hash()); QString hash = misc::toQString(h.info_hash());
return (hash == new_h.hash()); return (hash == new_h.hash());
} }

View file

@ -144,6 +144,8 @@ public:
} }
static void saveTorrentPersistentData(QTorrentHandle h, bool is_magnet = false) { static void saveTorrentPersistentData(QTorrentHandle h, bool is_magnet = false) {
Q_ASSERT(h.is_valid());
qDebug("Saving persistent data for %s", h.hash().toUtf8().data());
// First, remove temp data // First, remove temp data
TorrentTempData::deleteTempData(h.hash()); TorrentTempData::deleteTempData(h.hash());
Q_ASSERT(!TorrentTempData::hasTempData(h.hash())); Q_ASSERT(!TorrentTempData::hasTempData(h.hash()));
@ -151,7 +153,6 @@ public:
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash(); QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data; QHash<QString, QVariant> data;
data["hash"] = h.hash();
data["is_magnet"] = is_magnet; data["is_magnet"] = is_magnet;
if(is_magnet) { if(is_magnet) {
data["magnet_uri"] = misc::toQString(make_magnet_uri(h.get_torrent_handle())); data["magnet_uri"] = misc::toQString(make_magnet_uri(h.get_torrent_handle()));
@ -175,15 +176,18 @@ public:
tr_it++; tr_it++;
} }
data["trackers"] = trackers; data["trackers"] = trackers;
if(!is_magnet) {
QVariantList url_seeds; QVariantList url_seeds;
foreach(QString url_seed, h.url_seeds()) { foreach(QString url_seed, h.url_seeds()) {
url_seeds << url_seed; url_seeds << url_seed;
} }
data["url_seeds"] = url_seeds; data["url_seeds"] = url_seeds;
}
data["sequential"] = h.is_sequential_download(); data["sequential"] = h.is_sequential_download();
// Save data // Save data
all_data[h.hash()] = data; all_data[h.hash()] = data;
settings.setValue("torrents", all_data); settings.setValue("torrents", all_data);
qDebug("TorrentPersistentData: Saving save_path %s, hash: %s", h.save_path().toUtf8().data(), h.hash().toUtf8().data());
} }
static void saveTrackers(QTorrentHandle h) { static void saveTrackers(QTorrentHandle h) {
@ -222,12 +226,14 @@ public:
} }
static void saveSavePath(QString hash, QString save_path) { static void saveSavePath(QString hash, QString save_path) {
Q_ASSERT(!hash.isEmpty());
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash(); QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash(); QHash<QString, QVariant> data = all_data[hash].toHash();
data["save_path"] = save_path; data["save_path"] = save_path;
all_data[hash] = data; all_data[hash] = data;
settings.setValue("torrents", all_data); settings.setValue("torrents", all_data);
qDebug("TorrentPersistentData: Saving save_path: %s, hash: %s", save_path.toUtf8().data(), hash.toUtf8().data());
} }
static void saveUrlSeeds(QTorrentHandle h) { static void saveUrlSeeds(QTorrentHandle h) {
@ -289,6 +295,7 @@ public:
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash(); QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash(); QHash<QString, QVariant> data = all_data[hash].toHash();
qDebug("TorrentPersistentData: getSavePath %s", data["save_path"].toString().toUtf8().data());
return data["save_path"].toString(); return data["save_path"].toString();
} }
@ -303,8 +310,11 @@ public:
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash(); QHash<QString, QVariant> all_data = settings.value("torrents", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash(); QHash<QString, QVariant> data = all_data[hash].toHash();
if(data.contains("url_seeds")) {
return data["url_seeds"].toList(); return data["url_seeds"].toList();
} }
return QVariantList();
}
static bool isSeed(QString hash) { static bool isSeed(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));