qBittorrent/src/qtlibtorrent/qtorrenthandle.cpp

668 lines
21 KiB
C++
Raw Normal View History

/*
* 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
*/
#include <QString>
#include <QStringList>
#include <QFile>
#include <QDir>
#include <QByteArray>
#include <math.h>
#include "fs_utils.h"
#include "misc.h"
#include "preferences.h"
#include "qtorrenthandle.h"
#include "torrentpersistentdata.h"
#include <libtorrent/version.hpp>
#include <libtorrent/magnet_uri.hpp>
#include <libtorrent/torrent_info.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#ifdef Q_OS_WIN
#include <Windows.h>
#endif
using namespace libtorrent;
using namespace std;
2012-02-21 21:49:43 +04:00
static QPair<int, int> get_file_extremity_pieces(const torrent_info& t, int file_index)
{
const int num_pieces = t.num_pieces();
const int piece_size = t.piece_length();
const file_entry& file = t.file_at(file_index);
// Determine the first and last piece of the file
int first_piece = floor((file.offset + 1) / (float) piece_size);
Q_ASSERT(first_piece >= 0 && first_piece < num_pieces);
qDebug("First piece of the file is %d/%d", first_piece, num_pieces - 1);
int num_pieces_in_file = ceil(file.size / (float) piece_size);
int last_piece = first_piece + num_pieces_in_file - 1;
Q_ASSERT(last_piece >= 0 && last_piece < num_pieces);
qDebug("last piece of the file is %d/%d", last_piece, num_pieces - 1);
return qMakePair(first_piece, last_piece);
}
QTorrentHandle::QTorrentHandle(const torrent_handle& h): torrent_handle(h) {}
//
// Getters
//
QString QTorrentHandle::hash() const {
return misc::toQString(torrent_handle::info_hash());
}
QString QTorrentHandle::name() const {
QString name = TorrentPersistentData::getName(hash());
2012-02-20 21:30:53 +04:00
if (name.isEmpty()) {
#if LIBTORRENT_VERSION_NUM < 10000
name = misc::toQStringU(torrent_handle::name());
#else
2014-05-14 02:09:45 +04:00
name = misc::toQStringU(status(query_name).name);
#endif
}
return name;
}
QString QTorrentHandle::creation_date() const {
#if LIBTORRENT_VERSION_NUM < 10000
boost::optional<time_t> t = torrent_handle::get_torrent_info().creation_date();
#else
boost::optional<time_t> t = torrent_handle::torrent_file()->creation_date();
#endif
2012-05-15 20:57:31 +04:00
return t ? misc::toQString(*t) : "";
}
QString QTorrentHandle::current_tracker() const {
2014-05-14 02:09:45 +04:00
return misc::toQString(status(0x0).current_tracker);
}
bool QTorrentHandle::is_paused() const {
2014-05-14 02:09:45 +04:00
return is_paused(status(0x0));
}
bool QTorrentHandle::is_queued() const {
2014-05-14 02:09:45 +04:00
return is_queued(status(0x0));
}
size_type QTorrentHandle::total_size() const {
#if LIBTORRENT_VERSION_NUM < 10000
return torrent_handle::get_torrent_info().total_size();
#else
return torrent_handle::torrent_file()->total_size();
#endif
}
size_type QTorrentHandle::piece_length() const {
#if LIBTORRENT_VERSION_NUM < 10000
return torrent_handle::get_torrent_info().piece_length();
#else
return torrent_handle::torrent_file()->piece_length();
#endif
}
int QTorrentHandle::num_pieces() const {
#if LIBTORRENT_VERSION_NUM < 10000
return torrent_handle::get_torrent_info().num_pieces();
#else
return torrent_handle::torrent_file()->num_pieces();
#endif
2009-11-14 13:37:45 +03:00
}
bool QTorrentHandle::first_last_piece_first() const {
#if LIBTORRENT_VERSION_NUM < 10000
torrent_info const* t = &get_torrent_info();
#else
boost::intrusive_ptr<torrent_info const> t = torrent_file();
#endif
2012-02-21 21:49:43 +04:00
// Get int first media file
int index = 0;
for (index = 0; index < t->num_files(); ++index) {
QString path = misc::toQStringU(t->file_at(index).path);
const QString ext = fsutils::fileExtension(path);
2012-02-21 21:49:43 +04:00
if (misc::isPreviewable(ext) && torrent_handle::file_priority(index) > 0)
break;
}
2012-02-21 21:49:43 +04:00
if (index >= t->num_files()) // No media file
2012-02-21 21:49:43 +04:00
return false;
QPair<int, int> extremities = get_file_extremity_pieces(*t, index);
2012-02-21 21:49:43 +04:00
return (torrent_handle::piece_priority(extremities.first) == 7)
&& (torrent_handle::piece_priority(extremities.second) == 7);
}
QString QTorrentHandle::save_path() const {
#if LIBTORRENT_VERSION_NUM < 10000
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::save_path()));
#else
return fsutils::fromNativePath(misc::toQStringU(status(torrent_handle::query_save_path).save_path));
#endif
}
QString QTorrentHandle::save_path_parsed() const {
QString p;
if (has_metadata() && num_files() == 1) {
p = firstFileSavePath();
} else {
p = fsutils::fromNativePath(TorrentPersistentData::getSavePath(hash()));
if (p.isEmpty())
p = save_path();
}
return p;
}
QStringList QTorrentHandle::url_seeds() const {
QStringList res;
try {
const std::set<std::string> existing_seeds = torrent_handle::url_seeds();
2012-07-14 02:28:23 +04:00
std::set<std::string>::const_iterator it = existing_seeds.begin();
std::set<std::string>::const_iterator itend = existing_seeds.end();
for ( ; it != itend; ++it) {
2010-10-10 19:39:08 +04:00
qDebug("URL Seed: %s", it->c_str());
res << misc::toQString(*it);
}
} catch(std::exception &e) {
2010-10-10 19:39:08 +04:00
std::cout << "ERROR: Failed to convert the URL seed" << std::endl;
}
return res;
}
// get the size of the torrent without the filtered files
2011-04-17 14:29:44 +04:00
size_type QTorrentHandle::actual_size() const {
2014-05-14 02:09:45 +04:00
return status(query_accurate_download_counters).total_wanted;
}
bool QTorrentHandle::has_filtered_pieces() const {
2012-02-21 21:49:43 +04:00
const std::vector<int> piece_priorities = torrent_handle::piece_priorities();
foreach (const int priority, piece_priorities) {
if (priority == 0)
return true;
}
return false;
}
int QTorrentHandle::num_files() const {
#if LIBTORRENT_VERSION_NUM < 10000
return torrent_handle::get_torrent_info().num_files();
#else
return torrent_handle::torrent_file()->num_files();
#endif
}
QString QTorrentHandle::filename_at(unsigned int index) const {
#if LIBTORRENT_VERSION_NUM < 10000
Q_ASSERT(index < (unsigned int)torrent_handle::get_torrent_info().num_files());
#else
Q_ASSERT(index < (unsigned int)torrent_handle::torrent_file()->num_files());
#endif
return fsutils::fileName(filepath_at(index));
}
size_type QTorrentHandle::filesize_at(unsigned int index) const {
#if LIBTORRENT_VERSION_NUM < 10000
Q_ASSERT(index < (unsigned int)torrent_handle::get_torrent_info().num_files());
return torrent_handle::get_torrent_info().files().file_size(index);
#else
Q_ASSERT(index < (unsigned int)torrent_handle::torrent_file()->num_files());
return torrent_handle::torrent_file()->files().file_size(index);
#endif
}
QString QTorrentHandle::filepath_at(unsigned int index) const {
#if LIBTORRENT_VERSION_NUM < 10000
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::get_torrent_info().files().file_path(index)));
#else
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::torrent_file()->files().file_path(index)));
#endif
}
QString QTorrentHandle::orig_filepath_at(unsigned int index) const {
#if LIBTORRENT_VERSION_NUM < 10000
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::get_torrent_info().orig_files().file_path(index)));
#else
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::torrent_file()->orig_files().file_path(index)));
#endif
}
torrent_status::state_t QTorrentHandle::state() const {
2014-05-14 02:09:45 +04:00
return status(0x0).state;
}
QString QTorrentHandle::creator() const {
#if LIBTORRENT_VERSION_NUM < 10000
return misc::toQStringU(torrent_handle::get_torrent_info().creator());
#else
return misc::toQStringU(torrent_handle::torrent_file()->creator());
#endif
}
QString QTorrentHandle::comment() const {
#if LIBTORRENT_VERSION_NUM < 10000
return misc::toQStringU(torrent_handle::get_torrent_info().comment());
#else
return misc::toQStringU(torrent_handle::torrent_file()->comment());
#endif
}
bool QTorrentHandle::is_checking() const {
2014-05-14 02:09:45 +04:00
return is_checking(status(0x0));
}
// Return a list of absolute paths corresponding
// to all files in a torrent
2011-04-17 14:29:44 +04:00
QStringList QTorrentHandle::absolute_files_path() const {
QDir saveDir(save_path());
QStringList res;
2012-02-20 21:30:53 +04:00
for (int i = 0; i<num_files(); ++i) {
res << fsutils::expandPathAbs(saveDir.absoluteFilePath(filepath_at(i)));
}
return res;
}
2011-04-17 14:29:44 +04:00
QStringList QTorrentHandle::absolute_files_path_uneeded() const {
QDir saveDir(save_path());
QStringList res;
std::vector<int> fp = torrent_handle::file_priorities();
2012-02-20 21:30:53 +04:00
for (uint i = 0; i < fp.size(); ++i) {
if (fp[i] == 0) {
const QString file_path = fsutils::expandPathAbs(saveDir.absoluteFilePath(filepath_at(i)));
2012-02-20 21:30:53 +04:00
if (file_path.contains(".unwanted"))
res << file_path;
}
}
return res;
}
2010-08-22 00:22:59 +04:00
bool QTorrentHandle::has_missing_files() const {
2011-04-17 14:29:44 +04:00
const QStringList paths = absolute_files_path();
2012-02-20 21:30:53 +04:00
foreach (const QString &path, paths) {
if (!QFile::exists(path)) return true;
2010-08-22 00:22:59 +04:00
}
return false;
}
int QTorrentHandle::queue_position() const {
return queue_position(status(0x0));
}
bool QTorrentHandle::is_seed() const {
// Affected by bug http://code.rasterbar.com/libtorrent/ticket/402
//return torrent_handle::is_seed();
// May suffer from approximation problems
//return (progress() == 1.);
// This looks safe
2014-05-14 02:09:45 +04:00
return is_seed(status(0x0));
}
2011-04-17 14:36:50 +04:00
bool QTorrentHandle::is_sequential_download() const {
2014-05-14 02:09:45 +04:00
return status(0x0).sequential_download;
}
2009-11-19 18:43:00 +03:00
bool QTorrentHandle::priv() const {
if (!has_metadata())
return false;
#if LIBTORRENT_VERSION_NUM < 10000
return torrent_handle::get_torrent_info().priv();
#else
return torrent_handle::torrent_file()->priv();
#endif
2009-11-19 18:43:00 +03:00
}
QString QTorrentHandle::firstFileSavePath() const {
Q_ASSERT(has_metadata());
QString fsave_path = fsutils::fromNativePath(TorrentPersistentData::getSavePath(hash()));
2012-02-20 21:30:53 +04:00
if (fsave_path.isEmpty())
fsave_path = save_path();
2012-02-20 21:30:53 +04:00
if (!fsave_path.endsWith("/"))
fsave_path += "/";
fsave_path += filepath_at(0);
// Remove .!qB extension
2012-02-20 21:30:53 +04:00
if (fsave_path.endsWith(".!qB", Qt::CaseInsensitive))
fsave_path.chop(4);
return fsave_path;
}
QString QTorrentHandle::root_path() const
{
if (num_files() < 2)
return save_path();
QString first_filepath = filepath_at(0);
const int slashIndex = first_filepath.indexOf("/");
if (slashIndex >= 0)
return QDir(save_path()).absoluteFilePath(first_filepath.left(slashIndex));
return save_path();
}
bool QTorrentHandle::has_error() const {
2014-05-14 02:09:45 +04:00
return has_error(status(0x0));
}
QString QTorrentHandle::error() const {
2014-05-14 02:09:45 +04:00
return misc::toQString(status(0x0).error);
}
void QTorrentHandle::downloading_pieces(bitfield &bf) const {
std::vector<partial_piece_info> queue;
torrent_handle::get_download_queue(queue);
2012-07-14 02:28:23 +04:00
std::vector<partial_piece_info>::const_iterator it = queue.begin();
std::vector<partial_piece_info>::const_iterator itend = queue.end();
for ( ; it!= itend; ++it) {
bf.set_bit(it->piece_index);
}
return;
}
bool QTorrentHandle::has_metadata() const {
2014-05-14 02:09:45 +04:00
return status(0x0).has_metadata;
2011-04-17 19:00:48 +04:00
}
void QTorrentHandle::file_progress(std::vector<size_type>& fp) const {
2012-02-18 18:44:20 +04:00
torrent_handle::file_progress(fp, torrent_handle::piece_granularity);
}
//
// Setters
//
2010-11-24 23:31:14 +03:00
void QTorrentHandle::pause() const {
torrent_handle::auto_managed(false);
torrent_handle::pause();
torrent_handle::save_resume_data();
}
2010-11-24 23:31:14 +03:00
void QTorrentHandle::resume() const {
2012-02-21 21:49:43 +04:00
if (has_error())
torrent_handle::clear_error();
const QString torrent_hash = hash();
bool has_persistant_error = TorrentPersistentData::hasError(torrent_hash);
TorrentPersistentData::setErrorState(torrent_hash, false);
bool temp_path_enabled = Preferences().isTempPathEnabled();
2012-02-20 21:30:53 +04:00
if (has_persistant_error && temp_path_enabled) {
// Torrent was supposed to be seeding, checking again in final destination
qDebug("Resuming a torrent with error...");
const QString final_save_path = TorrentPersistentData::getSavePath(torrent_hash);
qDebug("Torrent final path is: %s", qPrintable(final_save_path));
2012-02-20 21:30:53 +04:00
if (!final_save_path.isEmpty())
move_storage(final_save_path);
}
torrent_handle::auto_managed(true);
torrent_handle::resume();
2012-02-20 21:30:53 +04:00
if (has_persistant_error && temp_path_enabled) {
// Force recheck
torrent_handle::force_recheck();
}
}
2012-02-21 21:49:43 +04:00
void QTorrentHandle::remove_url_seed(const QString& seed) const {
torrent_handle::remove_url_seed(seed.toStdString());
}
2012-02-21 21:49:43 +04:00
void QTorrentHandle::add_url_seed(const QString& seed) const {
2010-10-10 19:39:08 +04:00
const std::string str_seed = seed.toStdString();
qDebug("calling torrent_handle::add_url_seed(%s)", str_seed.c_str());
torrent_handle::add_url_seed(str_seed);
}
2012-02-21 21:49:43 +04:00
void QTorrentHandle::set_tracker_login(const QString& username, const QString& password) const {
torrent_handle::set_tracker_login(std::string(username.toLocal8Bit().constData()), std::string(password.toLocal8Bit().constData()));
2008-11-02 16:53:45 +03:00
}
2012-02-21 21:49:43 +04:00
void QTorrentHandle::move_storage(const QString& new_path) const {
Speedup and fix a bug in torrent moving. This commit implements a map where qbittorrent store a state of current torrent movings. This commit speed up torrents moving a bit and also fix a bug when qbittorrent doesn't do cleanup action when a single torrent is moved several times without waiting for a previous move to complete. How it worked before. Libtorrent has a function torrent_handle::move_storage() that allows to move a torrent to a specific directory. This function is asynchorous. It means that this function quits instantaneously and when the actual operation completes the alert 'storage_moved_alert' or 'storage_moved_failed_alert' will be sent. The storage_moved_alert contains a torrent_handle and a new path to where the torrent is moved. During handling of storage_moved_alert, qbittorrent needs not only new path, but also an old path to perform some of cleanup actions (like removing an old folder if it is empty). This was achieved by storing a value named 'previous save path' in TorrentPersistentData. A previous save path is written when move_storage() is issued and is read when storage_moved_alert is received. Problems. This mechanism has two negative aspects: 1. TorrentPersistentData is very slow. As torrent_handle::move_storage() is asynchoronous, TorrentPersistentData is responsible for more that 99.8% of time QTorrentHandle::move_storage(). This percent could be higher when there are lots of torrents and lower when there are few of them. 2. TorrentPersistentData stores only one previous path. But many move_storage()'s could be issued without waiting for previous to complete. Subsequent move_storage()'s overwrites previous save path of a previous move. A fix. The fix is simple. Before issueing move_storage() the oldPath is stored in a special map called 'torrentMoveStates'. When a storage_moved_alert is received the map is consulted and an alert is handled. When user moves torrent when previous moving have not yet finished, the new location is saved in a field 'queuedPath' the same map. When torrent moving is completed (or failed) qbittorrent attemps to perform move again to the queued location. Future direction. This fix removes one slow read and one slow write to TorrentPersistentData on torrent moving, but there is still exists TorrentPersistentData::saveSavePath in handleStorageMovedAlert(), so overall time for UI hang should be reduced only threefold. A speeding up TorrentPersistentData should be addressed in a separate commit. I don't know if I should clean up torrentMoveStates when torrent is deleted. In any case, torrent could be deleted when corresponding alert is in alert queue. So if we decide to clean up torrentMoveStates, then we should not treat receiving alert from unknown torrent as a error.
2014-06-18 00:43:25 +04:00
QString hashstr = hash();
if (TorrentTempData::isMoveInProgress(hashstr)) {
qDebug("enqueue move storage to %s", qPrintable(new_path));
TorrentTempData::enqueueMove(hashstr, new_path);
}
else {
QString old_path = save_path();
qDebug("move storage: %s to %s", qPrintable(old_path), qPrintable(new_path));
if (QDir(old_path) == QDir(new_path))
return;
TorrentTempData::startMove(hashstr, old_path, new_path);
// Create destination directory if necessary
// or move_storage() will fail...
QDir().mkpath(new_path);
// Actually move the storage
torrent_handle::move_storage(fsutils::toNativePath(new_path).toUtf8().constData());
}
}
2012-02-21 21:49:43 +04:00
bool QTorrentHandle::save_torrent_file(const QString& path) const {
2012-02-20 21:30:53 +04:00
if (!has_metadata()) return false;
#if LIBTORRENT_VERSION_NUM < 10000
torrent_info const* t = &get_torrent_info();
#else
boost::intrusive_ptr<torrent_info const> t = torrent_file();
#endif
2012-02-21 21:49:43 +04:00
entry meta = bdecode(t->metadata().get(),
t->metadata().get() + t->metadata_size());
entry torrent_entry(entry::dictionary_t);
torrent_entry["info"] = meta;
2012-02-20 21:30:53 +04:00
if (!torrent_handle::trackers().empty())
torrent_entry["announce"] = torrent_handle::trackers().front().url;
vector<char> out;
bencode(back_inserter(out), torrent_entry);
QFile torrent_file(path);
if (!out.empty() && torrent_file.open(QIODevice::WriteOnly)) {
torrent_file.write(&out[0], out.size());
torrent_file.close();
return true;
}
return false;
}
void QTorrentHandle::file_priority(int index, int priority) const {
vector<int> priorities = torrent_handle::file_priorities();
2012-02-20 21:30:53 +04:00
if (priorities[index] != priority) {
priorities[index] = priority;
prioritize_files(priorities);
}
}
void QTorrentHandle::prioritize_files(const vector<int> &files) const {
#if LIBTORRENT_VERSION_NUM < 10000
2012-02-20 21:30:53 +04:00
if ((int)files.size() != torrent_handle::get_torrent_info().num_files()) return;
#else
if ((int)files.size() != torrent_handle::torrent_file()->num_files()) return;
#endif
qDebug() << Q_FUNC_INFO;
bool was_seed = is_seed();
2011-01-08 16:48:29 +03:00
vector<size_type> progress;
file_progress(progress);
qDebug() << Q_FUNC_INFO << "Changing files priorities...";
torrent_handle::prioritize_files(files);
qDebug() << Q_FUNC_INFO << "Moving unwanted files to .unwanted folder and conversely...";
QString spath = save_path();
2012-02-21 21:49:43 +04:00
for (uint i = 0; i < files.size(); ++i) {
// Move unwanted files to a .unwanted subfolder
if (files[i] == 0) {
QString old_abspath = QDir(spath).absoluteFilePath(filepath_at(i));
QString parent_abspath = fsutils::branchPath(old_abspath);
// Make sure the file does not already exists
if (QDir(parent_abspath).dirName() != ".unwanted") {
QString unwanted_abspath = parent_abspath+"/.unwanted";
QString new_abspath = unwanted_abspath+"/"+filename_at(i);
qDebug() << "Unwanted path is" << unwanted_abspath;
if (QFile::exists(new_abspath)) {
qWarning() << "File" << new_abspath << "already exists at destination.";
continue;
}
bool created = QDir().mkpath(unwanted_abspath);
#ifdef Q_OS_WIN
qDebug() << "unwanted folder was created:" << created;
2012-02-20 21:30:53 +04:00
if (created) {
// Hide the folder on Windows
qDebug() << "Hiding folder (Windows)";
wstring win_path = fsutils::toNativePath(unwanted_abspath).toStdWString();
DWORD dwAttrs = GetFileAttributesW(win_path.c_str());
bool ret = SetFileAttributesW(win_path.c_str(), dwAttrs|FILE_ATTRIBUTE_HIDDEN);
Q_ASSERT(ret != 0); Q_UNUSED(ret);
}
#else
Q_UNUSED(created);
#endif
QString parent_path = fsutils::branchPath(filepath_at(i));
2012-02-20 21:30:53 +04:00
if (!parent_path.isEmpty() && !parent_path.endsWith("/"))
parent_path += "/";
rename_file(i, parent_path+".unwanted/"+filename_at(i));
}
}
// Move wanted files back to their original folder
2012-02-20 21:30:53 +04:00
if (files[i] > 0) {
QString parent_relpath = fsutils::branchPath(filepath_at(i));
2012-02-20 21:30:53 +04:00
if (QDir(parent_relpath).dirName() == ".unwanted") {
QString old_name = filename_at(i);
QString new_relpath = fsutils::branchPath(parent_relpath);
if (new_relpath.isEmpty())
rename_file(i, old_name);
else
rename_file(i, QDir(new_relpath).filePath(old_name));
// Remove .unwanted directory if empty
qDebug() << "Attempting to remove .unwanted folder at " << QDir(spath + "/" + new_relpath).absoluteFilePath(".unwanted");
QDir(spath + "/" + new_relpath).rmdir(".unwanted");
}
}
}
2012-02-20 21:30:53 +04:00
if (was_seed && !is_seed()) {
qDebug() << "Torrent is no longer SEEDING";
// Save seed status
TorrentPersistentData::saveSeedStatus(*this);
// Move to temp folder if necessary
const Preferences pref;
2012-02-20 21:30:53 +04:00
if (pref.isTempPathEnabled()) {
QString tmp_path = pref.getTempPath();
qDebug() << "tmp folder is enabled, move torrent to " << tmp_path << " from " << spath;
move_storage(tmp_path);
}
}
}
void QTorrentHandle::prioritize_first_last_piece(int file_index, bool b) const {
// Determine the priority to set
2012-02-21 21:49:43 +04:00
int prio = b ? 7 : torrent_handle::file_priority(file_index);
#if LIBTORRENT_VERSION_NUM < 10000
torrent_info const* tf = &get_torrent_info();
#else
boost::intrusive_ptr<torrent_info const> tf = torrent_file();
#endif
QPair<int, int> extremities = get_file_extremity_pieces(*tf, file_index);
2012-02-21 21:49:43 +04:00
piece_priority(extremities.first, prio);
piece_priority(extremities.second, prio);
}
void QTorrentHandle::prioritize_first_last_piece(bool b) const {
2012-02-20 21:30:53 +04:00
if (!has_metadata()) return;
// Download first and last pieces first for all media files in the torrent
2012-02-21 21:49:43 +04:00
const uint nbfiles = num_files();
for (uint index = 0; index < nbfiles; ++index) {
2011-04-17 14:29:44 +04:00
const QString path = filepath_at(index);
const QString ext = fsutils::fileExtension(path);
2012-02-20 21:30:53 +04:00
if (misc::isPreviewable(ext) && torrent_handle::file_priority(index) > 0) {
2011-04-17 14:29:44 +04:00
qDebug() << "File" << path << "is previewable, toggle downloading of first/last pieces first";
prioritize_first_last_piece(index, b);
}
}
}
2012-02-21 21:49:43 +04:00
void QTorrentHandle::rename_file(int index, const QString& name) const {
qDebug() << Q_FUNC_INFO << index << name;
torrent_handle::rename_file(index, std::string(fsutils::toNativePath(name).toUtf8().constData()));
}
//
// Operators
//
2012-02-20 23:32:58 +04:00
bool QTorrentHandle::operator ==(const QTorrentHandle& new_h) const {
2012-02-21 21:49:43 +04:00
return info_hash() == new_h.info_hash();
}
2014-05-14 02:09:45 +04:00
2014-06-03 21:35:50 +04:00
bool QTorrentHandle::is_paused(const libtorrent::torrent_status &status) {
2014-05-14 02:09:45 +04:00
return status.paused && !status.auto_managed;
}
int QTorrentHandle::queue_position(const libtorrent::torrent_status &status) {
if (status.queue_position < 0)
return -1;
return status.queue_position+1;
}
2014-06-03 21:35:50 +04:00
bool QTorrentHandle::is_queued(const libtorrent::torrent_status &status) {
2014-05-14 02:09:45 +04:00
return status.paused && status.auto_managed;
}
2014-06-03 21:35:50 +04:00
bool QTorrentHandle::is_seed(const libtorrent::torrent_status &status) {
2014-05-14 02:09:45 +04:00
return status.state == torrent_status::finished
|| status.state == torrent_status::seeding;
}
2014-06-03 21:35:50 +04:00
bool QTorrentHandle::is_checking(const libtorrent::torrent_status &status) {
2014-05-14 02:09:45 +04:00
return status.state == torrent_status::checking_files
|| status.state == torrent_status::checking_resume_data;
}
2014-06-03 21:35:50 +04:00
bool QTorrentHandle::has_error(const libtorrent::torrent_status &status) {
2014-05-14 02:09:45 +04:00
return status.paused && !status.error.empty();
}
2014-06-03 21:35:50 +04:00
float QTorrentHandle::progress(const libtorrent::torrent_status &status) {
2014-05-14 02:09:45 +04:00
if (!status.total_wanted)
return 0.;
if (status.total_wanted_done == status.total_wanted)
return 1.;
float progress = (float) status.total_wanted_done / (float) status.total_wanted;
Q_ASSERT(progress >= 0.f && progress <= 1.f);
return progress;
}