From 6d1ad28d8c41260c6f5c200f6c1902f3e7434ec7 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Sat, 4 Dec 2010 20:47:20 +0000 Subject: [PATCH] FEATURE: Download first/last pieces first now applies to all media files in the torrent (Thanks Ahmad) --- Changelog | 2 + src/properties/propertieswidget.cpp | 340 ++++++++++++++-------------- src/qtlibtorrent/qtorrenthandle.cpp | 66 +++--- src/qtlibtorrent/qtorrenthandle.h | 180 ++++++++------- 4 files changed, 294 insertions(+), 294 deletions(-) diff --git a/Changelog b/Changelog index 83135529a..e81ad1f5a 100644 --- a/Changelog +++ b/Changelog @@ -14,6 +14,8 @@ - FEATURE: Optimized and improved the peer country resolution code - FEATURE: Download first/last pieces first when sequential download is enabled (Thanks Ahmad) + - FEATURE: Download first/last pieces first now applies to all media files + in the torrent (Thanks Ahmad) - BUGFIX: Fix SOCKS5 proxy authentication in search engine(closes #680072) - BUGFIX: Fix two advanced settings (ignore limits on LAN and protocol overhead inclusion in rate limiter) diff --git a/src/properties/propertieswidget.cpp b/src/properties/propertieswidget.cpp index 5b9b23d45..c4055582f 100644 --- a/src/properties/propertieswidget.cpp +++ b/src/properties/propertieswidget.cpp @@ -58,7 +58,7 @@ using namespace libtorrent; PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, TransferListWidget *transferList): - QWidget(parent), transferList(transferList), main_window(main_window) { + QWidget(parent), transferList(transferList), main_window(main_window) { setupUi(this); state = VISIBLE; @@ -565,192 +565,190 @@ void PropertiesWidget::renameSelectedFile() { #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS) if(h.filepath_at(i).compare(new_name, Qt::CaseSensitive) == 0) { #else - if(h.filepath_at(i).compare(new_name, Qt::CaseInsensitive) == 0) { + if(h.filepath_at(i).compare(new_name, Qt::CaseInsensitive) == 0) { #endif - // Display error message - QMessageBox::warning(this, tr("The file could not be renamed"), - tr("This name is already in use in this folder. Please use a different name."), - QMessageBox::Ok); - return; - } - } - const bool force_recheck = QFile::exists(h.save_path()+QDir::separator()+new_name); - qDebug("Renaming %s to %s", qPrintable(old_name), qPrintable(new_name)); - h.rename_file(file_index, new_name); - // Force recheck - if(force_recheck) h.force_recheck(); - // Rename if torrent files model too - if(new_name_last.endsWith(".!qB")) - new_name_last.chop(4); - PropListModel->setData(index, new_name_last); - } else { - // Folder renaming - QStringList path_items; - path_items << index.data().toString(); - QModelIndex parent = PropListModel->parent(index); - while(parent.isValid()) { - path_items.prepend(parent.data().toString()); - parent = PropListModel->parent(parent); + // Display error message + QMessageBox::warning(this, tr("The file could not be renamed"), + tr("This name is already in use in this folder. Please use a different name."), + QMessageBox::Ok); + return; } - const QString old_path = path_items.join("/"); - path_items.removeLast(); - path_items << new_name_last; - QString new_path = path_items.join("/"); - if(!new_path.endsWith("/")) new_path += "/"; - // Check for overwriting - const int num_files = h.num_files(); - for(int i=0; isetData(index, new_name_last); + } else { + // Folder renaming + QStringList path_items; + path_items << index.data().toString(); + QModelIndex parent = PropListModel->parent(index); + while(parent.isValid()) { + path_items.prepend(parent.data().toString()); + parent = PropListModel->parent(parent); + } + const QString old_path = path_items.join("/"); + path_items.removeLast(); + path_items << new_name_last; + QString new_path = path_items.join("/"); + if(!new_path.endsWith("/")) new_path += "/"; + // Check for overwriting + const int num_files = h.num_files(); + for(int i=0; isetData(index, new_name_last); - // Remove old folder - const QDir old_folder(h.save_path()+"/"+old_path); - int timeout = 10; - while(!misc::removeEmptyTree(old_folder.absolutePath()) && timeout > 0) { - SleeperThread::msleep(100); - --timeout; - } + QMessageBox::warning(this, tr("The folder could not be renamed"), + tr("This name is already in use in this folder. Please use a different name."), + QMessageBox::Ok); + return; } } - } - - void PropertiesWidget::askWebSeed(){ - bool ok; - // Ask user for a new url seed - const QString url_seed = QInputDialog::getText(this, tr("New url seed", "New HTTP source"), - tr("New url seed:"), QLineEdit::Normal, - QString::fromUtf8("http://www."), &ok); - if(!ok) return; - qDebug("Adding %s web seed", qPrintable(url_seed)); - if(!listWebSeeds->findItems(url_seed, Qt::MatchFixedString).empty()) { - QMessageBox::warning(this, tr("qBittorrent"), - tr("This url seed is already in the list."), - QMessageBox::Ok); - return; - } - h.add_url_seed(url_seed); - // Refresh the seeds list - loadUrlSeeds(); - } - - void PropertiesWidget::deleteSelectedUrlSeeds(){ - const QList selectedItems = listWebSeeds->selectedItems(); - bool change = false; - foreach(const QListWidgetItem *item, selectedItems){ - QString url_seed = item->text(); - h.remove_url_seed(url_seed); - change = true; + bool force_recheck = false; + // Replace path in all files + for(int i=0; isetData(index, new_name_last); + // Remove old folder + const QDir old_folder(h.save_path()+"/"+old_path); + int timeout = 10; + while(!misc::removeEmptyTree(old_folder.absolutePath()) && timeout > 0) { + SleeperThread::msleep(100); + --timeout; } } + } +} - bool PropertiesWidget::applyPriorities() { - qDebug("Saving files priorities"); - const std::vector priorities = PropListModel->getFilesPriorities(h.get_torrent_info().num_files()); - bool first_last_piece_first = false; - // Save first/last piece first option state - if(h.first_last_piece_first()) - first_last_piece_first = true; - // Prioritize the files - qDebug("prioritize files: %d", priorities[0]); - h.prioritize_files(priorities); - // Restore first/last piece first option if necessary - if(first_last_piece_first) - h.prioritize_first_last_piece(true); - return true; - } +void PropertiesWidget::askWebSeed(){ + bool ok; + // Ask user for a new url seed + const QString url_seed = QInputDialog::getText(this, tr("New url seed", "New HTTP source"), + tr("New url seed:"), QLineEdit::Normal, + QString::fromUtf8("http://www."), &ok); + if(!ok) return; + qDebug("Adding %s web seed", qPrintable(url_seed)); + if(!listWebSeeds->findItems(url_seed, Qt::MatchFixedString).empty()) { + QMessageBox::warning(this, tr("qBittorrent"), + tr("This url seed is already in the list."), + QMessageBox::Ok); + return; + } + h.add_url_seed(url_seed); + // Refresh the seeds list + loadUrlSeeds(); +} + +void PropertiesWidget::deleteSelectedUrlSeeds(){ + const QList selectedItems = listWebSeeds->selectedItems(); + bool change = false; + foreach(const QListWidgetItem *item, selectedItems){ + QString url_seed = item->text(); + h.remove_url_seed(url_seed); + change = true; + } + if(change){ + // Refresh list + loadUrlSeeds(); + } +} +bool PropertiesWidget::applyPriorities() { + qDebug("Saving files priorities"); + const std::vector priorities = PropListModel->getFilesPriorities(h.get_torrent_info().num_files()); + // Save first/last piece first option state + bool first_last_piece_first = h.first_last_piece_first(); + // Prioritize the files + qDebug("prioritize files: %d", priorities[0]); + h.prioritize_files(priorities); + // Restore first/last piece first option if necessary + if(first_last_piece_first) + h.prioritize_first_last_piece(true); + return true; +} - void PropertiesWidget::on_changeSavePathButton_clicked() { - if(!h.is_valid()) return; - QString new_path; - if(h.has_metadata() && h.num_files() == 1) { - new_path = QFileDialog::getSaveFileName(this, tr("Choose save path"), h.firstFileSavePath()); - } else { - const QDir saveDir(TorrentPersistentData::getSavePath(h.hash())); - QFileDialog dlg(this, tr("Choose save path"), saveDir.absolutePath()); - dlg.setConfirmOverwrite(false); - dlg.setFileMode(QFileDialog::Directory); - dlg.setOption(QFileDialog::ShowDirsOnly, true); - dlg.setFilter(QDir::AllDirs); - dlg.setAcceptMode(QFileDialog::AcceptSave); - dlg.setNameFilterDetailsVisible(false); - if(dlg.exec()) - new_path = dlg.selectedFiles().first(); - } - if(!new_path.isEmpty()){ - // Check if savePath exists - QString save_path_dir = new_path.replace("\\", "/"); - QString new_file_name; - if(h.has_metadata() && h.num_files() == 1) { - QStringList parts = save_path_dir.split("/"); - new_file_name = parts.takeLast(); // Skip file name - save_path_dir = parts.join("/"); - } - QDir savePath(misc::expandPath(save_path_dir)); - // Actually move storage - if(!QBtSession::instance()->useTemporaryFolder() || h.is_seed()) { - if(!savePath.exists()) savePath.mkpath(savePath.absolutePath()); - h.move_storage(savePath.absolutePath()); - } - // Update save_path in dialog - QString display_path; - if(h.has_metadata() && h.num_files() == 1) { - // Rename the file - Q_ASSERT(!new_file_name.isEmpty()); + +void PropertiesWidget::on_changeSavePathButton_clicked() { + if(!h.is_valid()) return; + QString new_path; + if(h.has_metadata() && h.num_files() == 1) { + new_path = QFileDialog::getSaveFileName(this, tr("Choose save path"), h.firstFileSavePath()); + } else { + const QDir saveDir(TorrentPersistentData::getSavePath(h.hash())); + QFileDialog dlg(this, tr("Choose save path"), saveDir.absolutePath()); + dlg.setConfirmOverwrite(false); + dlg.setFileMode(QFileDialog::Directory); + dlg.setOption(QFileDialog::ShowDirsOnly, true); + dlg.setFilter(QDir::AllDirs); + dlg.setAcceptMode(QFileDialog::AcceptSave); + dlg.setNameFilterDetailsVisible(false); + if(dlg.exec()) + new_path = dlg.selectedFiles().first(); + } + if(!new_path.isEmpty()){ + // Check if savePath exists + QString save_path_dir = new_path.replace("\\", "/"); + QString new_file_name; + if(h.has_metadata() && h.num_files() == 1) { + QStringList parts = save_path_dir.split("/"); + new_file_name = parts.takeLast(); // Skip file name + save_path_dir = parts.join("/"); + } + QDir savePath(misc::expandPath(save_path_dir)); + // Actually move storage + if(!QBtSession::instance()->useTemporaryFolder() || h.is_seed()) { + if(!savePath.exists()) savePath.mkpath(savePath.absolutePath()); + h.move_storage(savePath.absolutePath()); + } + // Update save_path in dialog + QString display_path; + if(h.has_metadata() && h.num_files() == 1) { + // Rename the file + Q_ASSERT(!new_file_name.isEmpty()); #if defined(Q_WS_WIN) || defined(Q_OS_OS2) - if(h.filename_at(0).compare(new_file_name, Qt::CaseInsensitive) != 0) { + if(h.filename_at(0).compare(new_file_name, Qt::CaseInsensitive) != 0) { #else - if(h.filename_at(0).compare(new_file_name, Qt::CaseSensitive) != 0) { + if(h.filename_at(0).compare(new_file_name, Qt::CaseSensitive) != 0) { #endif - qDebug("Renaming single file to %s", qPrintable(new_file_name)); - h.rename_file(0, new_file_name); - // Also rename it in the files list model - PropListModel->setData(PropListModel->index(0, 0), new_file_name); - } - display_path = h.firstFileSavePath(); - } else { - display_path = savePath.absolutePath(); - } -#if defined(Q_WS_WIN) || defined(Q_OS_OS2) - display_path = display_path.replace("/", "\\"); -#endif - save_path->setText(display_path); + qDebug("Renaming single file to %s", qPrintable(new_file_name)); + h.rename_file(0, new_file_name); + // Also rename it in the files list model + PropListModel->setData(PropListModel->index(0, 0), new_file_name); } + display_path = h.firstFileSavePath(); + } else { + display_path = savePath.absolutePath(); } +#if defined(Q_WS_WIN) || defined(Q_OS_OS2) + display_path = display_path.replace("/", "\\"); +#endif + save_path->setText(display_path); + } +} - void PropertiesWidget::filteredFilesChanged() { - if(h.is_valid()) { - applyPriorities(); - } - } +void PropertiesWidget::filteredFilesChanged() { + if(h.is_valid()) { + applyPriorities(); + } +} diff --git a/src/qtlibtorrent/qtorrenthandle.cpp b/src/qtlibtorrent/qtorrenthandle.cpp index 5a4cbfd3d..62fa06673 100644 --- a/src/qtlibtorrent/qtorrenthandle.cpp +++ b/src/qtlibtorrent/qtorrenthandle.cpp @@ -122,27 +122,23 @@ int QTorrentHandle::num_pieces() const { } bool QTorrentHandle::first_last_piece_first() const { - // Detect main file - int rank=0; - int main_file_index = 0; - file_entry main_file = torrent_handle::get_torrent_info().file_at(0); - torrent_info::file_iterator it = torrent_handle::get_torrent_info().begin_files(); - it++; ++rank; - while(it != torrent_handle::get_torrent_info().end_files()) { - if(it->size > main_file.size) { - main_file = *it; - main_file_index = rank; + // Detect first media file + torrent_info::file_iterator it; + int index = 0; + for(it = get_torrent_info().begin_files(); it != get_torrent_info().end_files(); it++) { + const QString ext = misc::toQStringU(it->path.string()).split(".").last(); + if(misc::isPreviewable(ext) && torrent_handle::file_priority(index) > 0) { + break; } - it++; - ++rank; + ++index; } - qDebug() << "Main file in the torrent is" << filepath(main_file); + file_entry media_file = torrent_handle::get_torrent_info().file_at(index); int piece_size = torrent_handle::get_torrent_info().piece_length(); Q_ASSERT(piece_size>0); - int first_piece = floor((main_file.offset+1)/(double)piece_size); + int first_piece = floor((media_file.offset+1)/(double)piece_size); Q_ASSERT(first_piece >= 0 && first_piece < torrent_handle::get_torrent_info().num_pieces()); qDebug("First piece of the file is %d/%d", first_piece, torrent_handle::get_torrent_info().num_pieces()-1); - int num_pieces_in_file = ceil(main_file.size/(double)piece_size); + int num_pieces_in_file = ceil(media_file.size/(double)piece_size); int last_piece = first_piece+num_pieces_in_file-1; Q_ASSERT(last_piece >= 0 && last_piece < torrent_handle::get_torrent_info().num_pieces()); qDebug("last piece of the file is %d/%d", last_piece, torrent_handle::get_torrent_info().num_pieces()-1); @@ -550,32 +546,18 @@ void QTorrentHandle::add_tracker(const announce_entry& url) const { #endif } -void QTorrentHandle::prioritize_first_last_piece(bool b) const { - // Detect main file - int rank=0; - int main_file_index = 0; - file_entry main_file = torrent_handle::get_torrent_info().file_at(0); - torrent_info::file_iterator it = torrent_handle::get_torrent_info().begin_files(); - it++; ++rank; - while(it != torrent_handle::get_torrent_info().end_files()) { - if(it->size > main_file.size) { - main_file = *it; - main_file_index = rank; - } - it++; - ++rank; - } - qDebug() << "Main file in the torrent is" << filepath(main_file); +void QTorrentHandle::prioritize_first_last_piece(int file_index, bool b) const { // Determine the priority to set int prio = 7; // MAX - if(!b) prio = torrent_handle::file_priority(main_file_index); - // Determine the first and last piece of the main file + if(!b) prio = torrent_handle::file_priority(file_index); + file_entry file = get_torrent_info().file_at(file_index); + // Determine the first and last piece of the file int piece_size = torrent_handle::get_torrent_info().piece_length(); Q_ASSERT(piece_size>0); - int first_piece = floor((main_file.offset+1)/(double)piece_size); + int first_piece = floor((file.offset+1)/(double)piece_size); Q_ASSERT(first_piece >= 0 && first_piece < torrent_handle::get_torrent_info().num_pieces()); qDebug("First piece of the file is %d/%d", first_piece, torrent_handle::get_torrent_info().num_pieces()-1); - int num_pieces_in_file = ceil(main_file.size/(double)piece_size); + int num_pieces_in_file = ceil(file.size/(double)piece_size); int last_piece = first_piece+num_pieces_in_file-1; Q_ASSERT(last_piece >= 0 && last_piece < torrent_handle::get_torrent_info().num_pieces()); qDebug("last piece of the file is %d/%d", last_piece, torrent_handle::get_torrent_info().num_pieces()-1); @@ -583,6 +565,20 @@ void QTorrentHandle::prioritize_first_last_piece(bool b) const { torrent_handle::piece_priority(last_piece, prio); } +void QTorrentHandle::prioritize_first_last_piece(bool b) const { + // Download first and last pieces first for all media files in the torrent + torrent_info::file_iterator it; + int index = 0; + for(it = get_torrent_info().begin_files(); it != get_torrent_info().end_files(); it++) { + const QString ext = misc::toQStringU(it->path.string()).split(".").last(); + if(misc::isPreviewable(ext) && torrent_handle::file_priority(index) > 0) { + qDebug() << "File" << it->path.string().c_str() << "is previewable, toggle downloading of first/last pieces first"; + prioritize_first_last_piece(index, b); + } + ++index; + } +} + void QTorrentHandle::rename_file(int index, QString name) const { torrent_handle::rename_file(index, std::string(name.toUtf8().constData())); } diff --git a/src/qtlibtorrent/qtorrenthandle.h b/src/qtlibtorrent/qtorrenthandle.h index 45464d667..6aa45e40e 100644 --- a/src/qtlibtorrent/qtorrenthandle.h +++ b/src/qtlibtorrent/qtorrenthandle.h @@ -42,99 +42,103 @@ class QStringList; // to interact well with Qt types class QTorrentHandle : public libtorrent::torrent_handle { - public: +public: - // - // Constructors - // + // + // Constructors + // - QTorrentHandle() {} - explicit QTorrentHandle(libtorrent::torrent_handle h); + QTorrentHandle() {} + explicit QTorrentHandle(libtorrent::torrent_handle h); - // - // Getters - // - QString hash() const; - QString name() const; - float progress() const; - libtorrent::bitfield pieces() const; - QString current_tracker() const; - bool is_paused() const; - bool has_filtered_pieces() const; - libtorrent::size_type total_size() const; - libtorrent::size_type piece_length() const; - int num_pieces() const; - libtorrent::size_type total_wanted_done() const; - libtorrent::size_type total_wanted() const; - float download_payload_rate() const; - float upload_payload_rate() const; - int num_connections() const; - int connections_limit() const; - int num_peers() const; - int num_seeds() const; - int num_complete() const; - int num_incomplete() const; - QString save_path() const; - QStringList url_seeds() const; - libtorrent::size_type actual_size() const; - int num_files() const; - int queue_position() const; - bool is_queued() const; - QString filename_at(unsigned int index) const; - libtorrent::size_type filesize_at(unsigned int index) const; - QString filepath_at(unsigned int index) const; - QString orig_filepath_at(unsigned int index) const; - QString filepath(const libtorrent::file_entry &f) const; - libtorrent::torrent_status::state_t state() const; - QString creator() const; - QString comment() const; - libtorrent::size_type total_failed_bytes() const; - libtorrent::size_type total_redundant_bytes() const; - libtorrent::size_type total_payload_download() const; - libtorrent::size_type total_payload_upload() const; - libtorrent::size_type all_time_upload() const; - libtorrent::size_type all_time_download() const; - libtorrent::size_type total_done() const; - QStringList files_path() const; - QStringList uneeded_files_path() const; - bool has_missing_files() const; - int num_uploads() const; - bool is_seed() const; - bool is_checking() const; - bool is_auto_managed() const; - qlonglong active_time() const; - qlonglong seeding_time() const; - QString creation_date() const; - QString next_announce() const; - qlonglong next_announce_s() const; - bool priv() const; - bool first_last_piece_first() const; - QString root_path() const; - QString firstFileSavePath() const; - bool has_error() const; - QString error() const; - void downloading_pieces(libtorrent::bitfield &bf) const; + // + // Getters + // + QString hash() const; + QString name() const; + float progress() const; + libtorrent::bitfield pieces() const; + QString current_tracker() const; + bool is_paused() const; + bool has_filtered_pieces() const; + libtorrent::size_type total_size() const; + libtorrent::size_type piece_length() const; + int num_pieces() const; + libtorrent::size_type total_wanted_done() const; + libtorrent::size_type total_wanted() const; + float download_payload_rate() const; + float upload_payload_rate() const; + int num_connections() const; + int connections_limit() const; + int num_peers() const; + int num_seeds() const; + int num_complete() const; + int num_incomplete() const; + QString save_path() const; + QStringList url_seeds() const; + libtorrent::size_type actual_size() const; + int num_files() const; + int queue_position() const; + bool is_queued() const; + QString filename_at(unsigned int index) const; + libtorrent::size_type filesize_at(unsigned int index) const; + QString filepath_at(unsigned int index) const; + QString orig_filepath_at(unsigned int index) const; + QString filepath(const libtorrent::file_entry &f) const; + libtorrent::torrent_status::state_t state() const; + QString creator() const; + QString comment() const; + libtorrent::size_type total_failed_bytes() const; + libtorrent::size_type total_redundant_bytes() const; + libtorrent::size_type total_payload_download() const; + libtorrent::size_type total_payload_upload() const; + libtorrent::size_type all_time_upload() const; + libtorrent::size_type all_time_download() const; + libtorrent::size_type total_done() const; + QStringList files_path() const; + QStringList uneeded_files_path() const; + bool has_missing_files() const; + int num_uploads() const; + bool is_seed() const; + bool is_checking() const; + bool is_auto_managed() const; + qlonglong active_time() const; + qlonglong seeding_time() const; + QString creation_date() const; + QString next_announce() const; + qlonglong next_announce_s() const; + bool priv() const; + bool first_last_piece_first() const; + QString root_path() const; + QString firstFileSavePath() const; + bool has_error() const; + QString error() const; + void downloading_pieces(libtorrent::bitfield &bf) const; - // - // Setters - // - void pause() const; - void resume() const; - void remove_url_seed(QString seed) const; - void add_url_seed(QString seed) const; - void prioritize_files(const std::vector &v) const; - void file_priority(int index, int priority) const; - void set_tracker_login(QString username, QString password) const; - void move_storage(QString path) const; - void add_tracker(const libtorrent::announce_entry& url) const; - void prioritize_first_last_piece(bool b) const; - void rename_file(int index, QString name) const; - bool save_torrent_file(QString path) const; + // + // Setters + // + void pause() const; + void resume() const; + void remove_url_seed(QString seed) const; + void add_url_seed(QString seed) const; + void prioritize_files(const std::vector &v) const; + void file_priority(int index, int priority) const; + void set_tracker_login(QString username, QString password) const; + void move_storage(QString path) const; + void add_tracker(const libtorrent::announce_entry& url) const; + void prioritize_first_last_piece(bool b) const; + void rename_file(int index, QString name) const; + bool save_torrent_file(QString path) const; + + // + // Operators + // + bool operator ==(const QTorrentHandle& new_h) const; + +private: + void prioritize_first_last_piece(int file_index, bool b) const; - // - // Operators - // - bool operator ==(const QTorrentHandle& new_h) const; }; #endif